py3-kms upload

This commit is contained in:
Matteo ℱan 2018-02-28 23:27:12 +01:00 committed by GitHub
parent 1d9f221bd1
commit fb67af7870
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 4739 additions and 0 deletions

741
py3-kms/aes.py Normal file
View File

@ -0,0 +1,741 @@
#!/usr/bin/env python3
# aes.py: implements AES - Advanced Encryption Standard
# from the SlowAES project, http://code.google.com/p/slowaes/
#
# Copyright (c) 2008 Josh Davis ( http://www.josh-davis.org ), Alex Martelli ( http://www.aleax.it )
#
# Ported from C code written by Laurent Haan ( http://www.progressive-coding.com )
# Licensed under the Apache License, Version 2.0
# http://www.apache.org/licenses/
#
"""
Ported to Python3 with minimal changements.
© Copyright 2018 Matteo an <SystemRage@protonmail.com>
"""
import os
import math
def append_PKCS7_padding(val):
""" Function to pad the given data to a multiple of 16-bytes by PKCS7 padding. """
numpads = 16 - (len(val) % 16)
return val + numpads * bytes(chr(numpads), 'utf-8')
def strip_PKCS7_padding(val):
""" Function to strip off PKCS7 padding. """
if len(val) % 16 or not val:
raise ValueError("String of len %d can't be PCKS7-padded" % len(val))
numpads = val[-1]
if numpads > 16:
raise ValueError("String ending with %r can't be PCKS7-padded" % val[-1])
return val[:-numpads]
class AES( object ):
""" Class implementing the Advanced Encryption Standard algorithm. """
#*py-kms*
v6 = False
# Valid key sizes
KeySize = {
"SIZE_128": 16,
"SIZE_192": 24,
"SIZE_256": 32
}
# Rijndael S-box
sbox = [ 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67,
0x2b, 0xfe, 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59,
0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7,
0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1,
0x71, 0xd8, 0x31, 0x15, 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05,
0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, 0x09, 0x83,
0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29,
0xe3, 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b,
0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, 0xd0, 0xef, 0xaa,
0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c,
0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc,
0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, 0x13, 0xec,
0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19,
0x73, 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee,
0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49,
0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4,
0xea, 0x65, 0x7a, 0xae, 0x08, 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6,
0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, 0x70,
0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9,
0x86, 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e,
0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, 0x8c, 0xa1,
0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0,
0x54, 0xbb, 0x16 ]
# Rijndael Inverted S-box
rsbox = [ 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3,
0x9e, 0x81, 0xf3, 0xd7, 0xfb, 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f,
0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, 0x54,
0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b,
0x42, 0xfa, 0xc3, 0x4e, 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24,
0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25, 0x72, 0xf8,
0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d,
0x65, 0xb6, 0x92, 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda,
0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84, 0x90, 0xd8, 0xab,
0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3,
0x45, 0x06, 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1,
0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, 0x3a, 0x91, 0x11, 0x41,
0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6,
0x73, 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9,
0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e, 0x47, 0xf1, 0x1a, 0x71, 0x1d,
0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b,
0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0,
0xfe, 0x78, 0xcd, 0x5a, 0xf4, 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07,
0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f, 0x60,
0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f,
0x93, 0xc9, 0x9c, 0xef, 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5,
0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, 0x17, 0x2b,
0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55,
0x21, 0x0c, 0x7d ]
# Rijndael Rcon
Rcon = [ 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36,
0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97,
0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72,
0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66,
0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04,
0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d,
0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3,
0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61,
0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a,
0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40,
0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc,
0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5,
0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a,
0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d,
0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c,
0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35,
0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4,
0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc,
0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08,
0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a,
0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d,
0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2,
0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74,
0xe8, 0xcb ]
def getSBoxValue(self,num):
""" Method to retrieve a given S-Box value. """
return self.sbox[num]
def getSBoxInvert(self,num):
""" Method to retrieve a given Inverted S-Box value."""
return self.rsbox[num]
def rotate(self, word):
""" Method performing Rijndael's key schedule rotate operation.
Rotate a word eight bits to the left: eg, rotate(1d2c3a4f) == 2c3a4f1d
@param word: char list of size 4 (32 bits overall).
"""
return word[1:] + word[:1]
def getRconValue(self, num):
""" Method to retrieve a given Rcon value. """
return self.Rcon[num]
def core(self, word, iteration):
""" Method performing the key schedule core operation. """
# Rotate the 32-bit word 8 bits to the left.
word = self.rotate(word)
# Apply S-Box substitution on all 4 parts of the 32-bit word.
for i in range(4):
word[i] = self.getSBoxValue(word[i])
# XOR the output of the rcon operation with i to the first part (leftmost) only.
word[0] = word[0] ^ self.getRconValue(iteration)
return word
def expandKey(self, key, size, expandedKeySize):
""" Method performing Rijndael's key expansion.
Expands an 128, 192, 256 key into an 176, 208, 240 bit key.
"""
# Current expanded keySize, in bytes.
currentSize = 0
rconIteration = 1
expandedKey = [0] * expandedKeySize
# Set the 16, 24, 32 bytes of the expanded key to the input key.
for j in range(size):
expandedKey[j] = key[j]
currentSize += size
while currentSize < expandedKeySize:
# Assign the previous 4 bytes to the temporary value t.
t = expandedKey[currentSize - 4:currentSize]
# Every 16,24,32 bytes we apply the core schedule to t
# and increment rconIteration afterwards.
if currentSize % size == 0:
t = self.core(t, rconIteration)
rconIteration += 1
# For 256-bit keys, we add an extra sbox to the calculation.
if size == self.KeySize["SIZE_256"] and ((currentSize % size) == 16):
for l in range(4):
t[l] = self.getSBoxValue(t[l])
# We XOR t with the four-byte block 16,24,32 bytes before the new
# expanded key. This becomes the next four bytes in the expanded key.
for m in range(4):
expandedKey[currentSize] = expandedKey[currentSize - size] ^ t[m]
currentSize += 1
return expandedKey
def addRoundKey(self, state, roundKey):
""" Method to add (XORs) the round key to the state. """
for i in range(16):
state[i] ^= roundKey[i]
return state
def createRoundKey(self, expandedKey, roundKeyPointer):
""" Creates a round key from the given expanded key and the
position within the expanded key.
"""
roundKey = [0] * 16
for i in range(4):
for j in range(4):
roundKey[j * 4 + i] = expandedKey[roundKeyPointer + i * 4 + j]
return roundKey
def galois_multiplication(self, a, b):
""" Method to perform a Galois multiplication of 8 bit characters
a and b.
"""
p = 0
for counter in range(8):
if b & 1:
p ^= a
hi_bit_set = a & 0x80
a <<= 1
# keep a 8 bit
a &= 0xFF
if hi_bit_set:
a ^= 0x1b
b >>= 1
return p
def subBytes(self, state, isInv):
""" Method to substitute all the values from the state with the
value in the SBox using the state value as index for the SBox.
"""
if isInv:
getter = self.getSBoxInvert
else:
getter = self.getSBoxValue
for i in range(16):
state[i] = getter(state[i])
return state
def shiftRows(self, state, isInv):
""" Method to iterate over the 4 rows and call shiftRow(...) with that row. """
for i in range(4):
state = self.shiftRow(state, i * 4, i, isInv)
return state
def shiftRow(self, state, statePointer, nbr, isInv):
""" Method to shift the row to the left. """
for i in range(nbr):
if isInv:
state[statePointer:statePointer + 4] = state[statePointer + 3:statePointer + 4] + \
state[statePointer:statePointer + 3]
else:
state[statePointer:statePointer + 4] = state[statePointer + 1:statePointer + 4] + \
state[statePointer:statePointer + 1]
return state
def mixColumns(self, state, isInv):
""" Method to perform a galois multiplication of the 4x4 matrix. """
# Iterate over the 4 columns.
for i in range(4):
# Construct one column by slicing over the 4 rows.
column = state[i:i + 16:4]
# Apply the mixColumn on one column.
column = self.mixColumn(column, isInv)
# Put the values back into the state.
state[i:i + 16:4] = column
return state
def mixColumn(self, column, isInv):
""" Method to perform a galois multiplication of 1 column the 4x4 matrix. """
if isInv:
mult = [14, 9, 13, 11]
else:
mult = [2, 1, 1, 3]
cpy = list(column)
g = self.galois_multiplication
column[0] = g(cpy[0], mult[0]) ^ g(cpy[3], mult[1]) ^ \
g(cpy[2], mult[2]) ^ g(cpy[1], mult[3])
column[1] = g(cpy[1], mult[0]) ^ g(cpy[0], mult[1]) ^ \
g(cpy[3], mult[2]) ^ g(cpy[2], mult[3])
column[2] = g(cpy[2], mult[0]) ^ g(cpy[1], mult[1]) ^ \
g(cpy[0], mult[2]) ^ g(cpy[3], mult[3])
column[3] = g(cpy[3], mult[0]) ^ g(cpy[2], mult[1]) ^ \
g(cpy[1], mult[2]) ^ g(cpy[0], mult[3])
return column
def aes_round(self, state, roundKey, roundKms):
""" Method to apply the 4 operations of the forward round in sequence. """
state = self.subBytes(state, False)
state = self.shiftRows(state, False)
state = self.mixColumns(state, False)
#*py-kms*
if self.v6:
if roundKms == 4:
state[0] ^= 0x73
if roundKms == 6:
state[0] ^= 0x09
if roundKms == 8:
state[0] ^= 0xE4
state = self.addRoundKey(state, roundKey)
return state
def aes_invRound(self, state, roundKey, roundKms):
""" Method to apply the 4 operations of the inverse round in sequence. """
state = self.shiftRows(state, True)
state = self.subBytes(state, True)
state = self.addRoundKey(state, roundKey)
#*py-kms*
if self.v6:
if roundKms == 4:
state[0] ^= 0x73
if roundKms == 6:
state[0] ^= 0x09
if roundKms == 8:
state[0] ^= 0xE4
state = self.mixColumns(state, True)
return state
def aes_main(self, state, expandedKey, nbrRounds):
""" Method to do the AES encryption for one round.
Perform the initial operations, the standard round and the
final operations of the forward AES, creating a round key for each round.
"""
state = self.addRoundKey(state, self.createRoundKey(expandedKey, 0))
i = 1
while i < nbrRounds:
state = self.aes_round(state, self.createRoundKey(expandedKey, 16 * i), i)
i += 1
state = self.subBytes(state, False)
state = self.shiftRows(state, False)
state = self.addRoundKey(state, self.createRoundKey(expandedKey, 16 * nbrRounds))
return state
def aes_invMain(self, state, expandedKey, nbrRounds):
""" Method to do the inverse AES encryption for one round.
Perform the initial operations, the standard round, and the
final operations of the inverse AES, creating a round key for each round.
"""
state = self.addRoundKey(state, self.createRoundKey(expandedKey, 16 * nbrRounds))
i = nbrRounds - 1
while i > 0:
state = self.aes_invRound(state, self.createRoundKey(expandedKey, 16 * i), i)
i -= 1
state = self.shiftRows(state, True)
state = self.subBytes(state, True)
state = self.addRoundKey(state, self.createRoundKey(expandedKey, 0))
return state
def encrypt(self, iput, key, size):
""" Method to encrypt a 128 bit input block against the given key
of size specified.
"""
output = [0] * 16
# The number of rounds.
nbrRounds = 0
# The 128 bit block to encode.
block = [0] * 16
# Set the number of rounds.
if size == self.KeySize["SIZE_128"]:
nbrRounds = 10
elif size == self.KeySize["SIZE_192"]:
nbrRounds = 12
elif size == self.KeySize["SIZE_256"]:
nbrRounds = 14
# *py-kms* The KMS v4 parameters.
elif size == 20:
nbrRounds = 11
else:
raise ValueError("Wrong key size given ({}).".format(size))
# The expanded keySize.
expandedKeySize = 16 * (nbrRounds + 1)
# Set the block values, for the block:
# a[0,0] a[0,1] a[0,2] a[0,3]
# a[1,0] a[1,1] a[1,2] a[1,3]
# a[2,0] a[2,1] a[2,2] a[2,3]
# a[3,0] a[3,1] a[3,2] a[3,3]
# the mapping order is a[0,0] a[1,0] a[2,0] a[3,0] a[0,1] a[1,1] ... a[2,3] a[3,3]
# Iterate over the columns and over the rows.
for i in range(4):
for j in range(4):
block[i + j * 4] = iput[i * 4 +j]
# Expand the key into an 176, 208, 240 bit key
expandedKey = self.expandKey(key, size, expandedKeySize)
# Encrypt the block using the expandedKey.
block = self.aes_main(block, expandedKey, nbrRounds)
# Unmap the block again into the output.
for k in range(4):
for l in range(4):
output[k * 4 + l] = block[k + l * 4]
return output
def decrypt(self, iput, key, size):
""" Method to decrypt a 128 bit input block against the given key
of size specified.
"""
output = [0] * 16
# The number of rounds.
nbrRounds = 0
# The 128 bit block to decode.
block = [0] * 16
# Set the number of rounds.
if size == self.KeySize["SIZE_128"]:
nbrRounds = 10
elif size == self.KeySize["SIZE_192"]:
nbrRounds = 12
elif size == self.KeySize["SIZE_256"]:
nbrRounds = 14
#*py-kms* The KMS v4 parameters.
elif size == 20:
nbrRounds = 11
else:
raise ValueError("Wrong key size given ({}).".format(size))
# The expanded keySize.
expandedKeySize = 16 * (nbrRounds + 1)
# Set the block values, for the block:
# a[0,0] a[0,1] a[0,2] a[0,3]
# a[1,0] a[1,1] a[1,2] a[1,3]
# a[2,0] a[2,1] a[2,2] a[2,3]
# a[3,0] a[3,1] a[3,2] a[3,3]
# the mapping order is a[0,0] a[1,0] a[2,0] a[3,0] a[0,1] a[1,1] ... a[2,3] a[3,3]
# Iterate over the columns and the rows.
for i in range(4):
for j in range(4):
block[i + j * 4] = iput[i * 4 + j]
# Expand the key into an 176, 208, 240 bit key.
expandedKey = self.expandKey(key, size, expandedKeySize)
# Decrypt the block using the expandedKey.
block = self.aes_invMain(block, expandedKey, nbrRounds)
# Unmap the block again into the output.
for k in range(4):
for l in range(4):
output[k * 4 +l] = block[k + l * 4]
return output
class AESModeOfOperation( object ):
""" Class implementing the different AES mode of operations. """
aes = AES()
# Supported modes of operation.
ModeOfOperation = {
"OFB": 0,
"CFB": 1,
"CBC": 2
}
def convertString(self, string, start, end, mode):
""" Method to convert a 16 character string into a number array. """
if end - start > 16:
end = start + 16
if mode == self.ModeOfOperation["CBC"]:
ar = [0] * 16
else:
ar = []
i = start
j = 0
while len(ar) < end - start:
ar.append(0)
while i < end:
ar[j] = string[i]
j += 1
i += 1
return ar
def encrypt(self, stringIn, mode, key, size, IV):
""" Method to perform the encryption operation.
@param stringIn: input string to be encrypted
@param mode: mode of operation (0, 1 or 2)
@param key: a hex key of the bit length size
@param size: the bit length of the key (16, 24 or 32)
@param IV: the 128 bit hex initilization vector
@return tuple with mode of operation, length of the input and the encrypted data
"""
if len(key) % size:
raise ValueError("Illegal size ({}) for key '{}'.".format(size, key))
if len(IV) % 16:
raise ValueError("IV is not a multiple of 16.")
# The AES input/output.
plaintext = []
iput = [0] * 16
output = []
ciphertext = [0] * 16
# The output cipher string.
cipherOut = []
firstRound = True
if stringIn != None:
for j in range(int(math.ceil(float(len(stringIn))/16))):
start = j * 16
end = j * 16 + 16
if end > len(stringIn):
end = len(stringIn)
plaintext = self.convertString(stringIn, start, end, mode)
if mode == self.ModeOfOperation["CFB"]:
if firstRound:
output = self.aes.encrypt(IV, key, size)
firstRound = False
else:
output = self.aes.encrypt(iput, key, size)
for i in range(16):
if len(plaintext) - 1 < i:
ciphertext[i] = 0 ^ output[i]
elif len(output) - 1 < i:
ciphertext[i] = plaintext[i] ^ 0
elif len(plaintext) - 1 < i and len(output) < i:
ciphertext[i] = 0 ^ 0
else:
ciphertext[i] = plaintext[i] ^ output[i]
for k in range(end - start):
cipherOut.append(ciphertext[k])
iput = ciphertext
elif mode == self.ModeOfOperation["OFB"]:
if firstRound:
output = self.aes.encrypt(IV, key, size)
firstRound = False
else:
output = self.aes.encrypt(iput, key, size)
for i in range(16):
if len(plaintext) - 1 < i:
ciphertext[i] = 0 ^ output[i]
elif len(output) - 1 < i:
ciphertext[i] = plaintext[i] ^ 0
elif len(plaintext) - 1 < i and len(output) < i:
ciphertext[i] = 0 ^ 0
else:
ciphertext[i] = plaintext[i] ^ output[i]
for k in range(end - start):
cipherOut.append(ciphertext[k])
iput = output
elif mode == self.ModeOfOperation["CBC"]:
for i in range(16):
if firstRound:
iput[i] = plaintext[i] ^ IV[i]
else:
iput[i] = plaintext[i] ^ ciphertext[i]
firstRound = False
ciphertext = self.aes.encrypt(iput, key, size)
# Always 16 bytes because of the padding for CBC.
for k in range(16):
cipherOut.append(ciphertext[k])
return mode, len(stringIn), cipherOut
def decrypt(self, cipherIn, originalsize, mode, key, size, IV):
""" Method to perform the decryption operation.
@param cipherIn: encrypted string to be decrypted
@param originalsize: unencrypted string length (required for CBC)
@param mode: mode of operation (0, 1 or 2)
@param key: a number array of the bit length size
@param size: the bit length of the key (16, 24 or 32)
@param IV: the 128 bit number array initilization vector
@return decrypted data
"""
if len(key) % size:
raise ValueError("Illegal size ({}) for key '{}'.".format(size, key))
if len(IV) % 16:
raise ValueError("IV is not a multiple of 16.")
# The AES input/output.
ciphertext = []
iput = []
output = []
plaintext = [0] * 16
# The output plain text character list.
chrOut = []
firstRound = True
if cipherIn != None:
for j in range(int(math.ceil(float(len(cipherIn))/16))):
start = j * 16
end = j * 16 + 16
if j * 16 + 16 > len(cipherIn):
end = len(cipherIn)
ciphertext = cipherIn[start:end]
if mode == self.ModeOfOperation["CFB"]:
if firstRound:
output = self.aes.encrypt(IV, key, size)
firstRound = False
else:
output = self.aes.encrypt(iput, key, size)
for i in range(16):
if len(output) - 1 < i:
plaintext[i] = 0 ^ ciphertext[i]
elif len(ciphertext) - 1 < i:
plaintext[i] = output[i] ^ 0
elif len(output) - 1 < i and len(ciphertext) < i:
plaintext[i] = 0 ^ 0
else:
plaintext[i] = output[i] ^ ciphertext[i]
for k in range(end - start):
chrOut.append(plaintext[k])
iput = ciphertext
elif mode == self.ModeOfOperation["OFB"]:
if firstRound:
output = self.aes.encrypt(IV, key, size)
firstRound = False
else:
output = self.aes.encrypt(iput, key, size)
for i in range(16):
if len(output) - 1 < i:
plaintext[i] = 0 ^ ciphertext[i]
elif len(ciphertext) - 1 < i:
plaintext[i] = output[i] ^ 0
elif len(output) - 1 < i and len(ciphertext) < i:
plaintext[i] = 0 ^ 0
else:
plaintext[i] = output[i] ^ ciphertext[i]
for k in range(end - start):
chrOut.append(plaintext[k])
iput = output
elif mode == self.ModeOfOperation["CBC"]:
output = self.aes.decrypt(ciphertext, key, size)
for i in range(16):
if firstRound:
plaintext[i] = IV[i] ^ output[i]
else:
plaintext[i] = iput[i] ^ output[i]
firstRound = False
if originalsize is not None and originalsize < end:
for k in range(originalsize - start):
chrOut.append(plaintext[k])
else:
for k in range(end - start):
chrOut.append(plaintext[k])
iput = ciphertext
return chrOut
def encryptData(key, data, mode=AESModeOfOperation.ModeOfOperation["CBC"]):
""" Module function to encrypt the given data with the given key.
@param key: key to be used for encryption
@param data: data to be encrypted
@param mode: mode of operations (0, 1 or 2)
@return encrypted data prepended with the initialization vector
"""
if mode == AESModeOfOperation.ModeOfOperation["CBC"]:
data = append_PKCS7_padding(data)
keysize = len(key)
assert keysize in AES.KeySize.values(), 'invalid key size: {}'.format(keysize)
# Create a new iv using random data.
iv = os.urandom(16)
moo = AESModeOfOperation()
(mode, length, ciph) = moo.encrypt(data, mode, key, keysize, iv)
# With padding, the original length does not need to be known.
# It's a bad idea to store the original message length prepend the iv.
return iv + bytes(ciph)
def decryptData(key, data, mode=AESModeOfOperation.ModeOfOperation["CBC"]):
""" Module function to decrypt the given data with the given key.
@param key: key to be used for decryption
@param data: data to be decrypted with initialization vector prepended
@param mode: mode of operations (0, 1 or 2)
@return decrypted data
"""
keysize = len(key)
assert keysize in AES.KeySize.values(), 'invalid key size: {}'.format(keysize)
# iv is first 16 bytes.
iv = data[:16]
data = data[16:]
moo = AESModeOfOperation()
decr = moo.decrypt(data, None, mode, key, keysize, iv)
if mode == AESModeOfOperation.ModeOfOperation["CBC"]:
decr = strip_PKCS7_padding(decr)
return decr
class Test(object):
def generateRandomKey(self, keysize):
""" Generates a key from random data of length `keysize`.
The returned key is a string of bytes.
"""
if keysize not in (16, 24, 32):
raise ValueError('Invalid keysize, %s. Should be one of (16, 24, 32).' % keysize)
return os.urandom(keysize)
def testString(self, cleartext, keysize = 16, modeName = "CBC"):
""" Test with random key, choice of mode. """
print('Random key test with Mode:', modeName)
print('ClearText:', cleartext)
key = self.generateRandomKey(keysize)
print('Key:', bytes([x for x in key]))
mode = AESModeOfOperation.ModeOfOperation[modeName]
cipher = encryptData(key, cleartext, mode)
print('Cipher:', bytes([x for x in cipher]))
decr = decryptData(key, cipher, mode)
print('Decrypted:', bytes(decr))
if __name__ == "__main__":
moo = AESModeOfOperation()
cleartext = "This is a test with several blocks ! Some utf-8 characters åäö and test continues"
print('ClearText: %s\n' % cleartext)
cleartext = bytes(cleartext, 'utf-8')
cipherkey = [143, 194, 34, 208, 145, 203, 230, 143, 177, 246, 97, 206, 145, 92, 255, 84]
iv = [103, 35, 148, 239, 76, 213, 47, 118, 255, 222, 123, 176, 106, 134, 98, 92]
mode, orig_len, ciph = moo.encrypt(cleartext, moo.ModeOfOperation["CBC"],
cipherkey, moo.aes.KeySize["SIZE_128"], iv)
print('Encrypt result: mode = %s, length = %s (%s), encrypted = %s\n' % (mode, orig_len, len(cleartext), bytes(ciph)))
decr = moo.decrypt(ciph, orig_len, mode, cipherkey, moo.aes.KeySize["SIZE_128"], iv)
print('Decrypt result: %s\n' % bytes(decr))
Test().testString(cleartext, 16, "CBC")

263
py3-kms/client.py Normal file
View File

@ -0,0 +1,263 @@
#!/usr/bin/env python3
import argparse
import binascii
import datetime
import random
import socket
import string
import struct
import sys
import uuid
import logging
import os
import filetimes, rpcBind, rpcRequest
from dcerpc import MSRPCHeader, MSRPCBindNak, MSRPCRequestHeader, MSRPCRespHeader
from kmsBase import kmsBase, UUID
from kmsRequestV4 import kmsRequestV4
from kmsRequestV5 import kmsRequestV5
from kmsRequestV6 import kmsRequestV6
from rpcBase import rpcBase
from formatText import shell_message, justify, byterize
config = {}
def main():
parser = argparse.ArgumentParser()
parser.add_argument("ip", action="store", help='The IP address or hostname of the KMS server.', type=str)
parser.add_argument("port", nargs="?", action="store", default=1688,
help='The port the KMS service is listening on. The default is \"1688\".', type=int)
parser.add_argument("-m", "--mode", dest="mode",
choices=["WindowsVista","Windows7","Windows8","Windows81","Windows10","Office2010","Office2013","Office2016"], default="Windows7",
help='Use this flag to manually specify a Microsoft product for testing the server. The default is \"Windows81\".', type=str)
parser.add_argument("-c", "--cmid", dest="cmid", default=None,
help='Use this flag to manually specify a CMID to use. If no CMID is specified, a random CMID will be generated.', type=str)
parser.add_argument("-n", "--name", dest="machineName", default=None,
help='Use this flag to manually specify an ASCII machineName to use. If no machineName is specified,\
a random machineName will be generated.', type=str)
parser.add_argument("-v", "--loglevel", dest="loglevel", action="store", default="ERROR", choices=["CRITICAL", "ERROR", "WARNING", "INFO", "DEBUG"],
help='Use this flag to set a Loglevel. The default is \"ERROR\".', type=str)
parser.add_argument("-f", "--logfile", dest="logfile", action="store", default=os.path.dirname(os.path.abspath( __file__ )) + "/py3kms_client.log",
help='Use this flag to set an output Logfile. The default is \"pykms_client.log\".', type=str)
config.update(vars(parser.parse_args()))
logging.basicConfig(level=config['loglevel'], format='%(asctime)s %(levelname)-8s %(message)s',
datefmt='%a, %d %b %Y %H:%M:%S', filename=config['logfile'], filemode='w')
checkConfig()
config['call_id'] = 1
updateConfig()
s = socket.socket()
logging.info("Connecting to %s on port %d..." % (config['ip'], config['port']))
s.connect((config['ip'], config['port']))
logging.info("Connection successful !")
binder = rpcBind.handler(None, config)
RPC_Bind = str(binder.generateRequest()).encode('latin-1') #*2to3*
logging.info("Sending RPC bind request...")
shell_message(nshell = [-1, 1])
s.send(RPC_Bind)
try:
shell_message(nshell = [-4, 7])
bindResponse = s.recv(1024)
except socket.error as e: #*2to3*
if e[0] == 104:
logging.error("Connection reset by peer. Exiting...")
sys.exit()
else:
raise
if bindResponse == '' or not bindResponse:
logging.error("No data received ! Exiting...")
sys.exit()
packetType = MSRPCHeader(bindResponse)['type']
if packetType == rpcBase.packetType['bindAck']:
logging.info("RPC bind acknowledged.")
shell_message(nshell = 8)
kmsRequest = createKmsRequest()
requester = rpcRequest.handler(kmsRequest, config)
s.send(str(requester.generateRequest()).encode('latin-1')) #*2to3*
shell_message(nshell = [-1, 12])
response = s.recv(1024)
logging.debug("Response: \n%s\n" % justify(binascii.b2a_hex(response).decode('latin-1'))) #*2to3*
shell_message(nshell = [-4, 20])
parsed = MSRPCRespHeader(response)
kmsData = readKmsResponse(parsed['pduData'], kmsRequest, config)
kmsResp = kmsData['response']
try:
hwid = kmsData['hwid']
except:
hwid = None
logging.info("KMS Host ePID: %s" % kmsResp['kmsEpid'].encode('utf-8').decode('utf-16le')) #*2to3*
if hwid is not None:
logging.info("KMS Host HWID: %s" % binascii.b2a_hex(hwid.encode('latin-1')).upper().decode('utf-8')) #*2to3*
logging.info("KMS Host Current Client Count: %s" % kmsResp['currentClientCount'])
logging.info("KMS VL Activation Interval: %s" % kmsResp['vLActivationInterval'])
logging.info("KMS VL Renewal Interval: %s" % kmsResp['vLRenewalInterval'])
shell_message(nshell = 21)
elif packetType == rpcBase.packetType['bindNak']:
logging.info(justify(MSRPCBindNak(bindResponse).dump(print_to_stdout = False)))
sys.exit()
else:
logging.critical("Something went wrong.")
sys.exit()
def checkConfig():
if config['cmid'] is not None:
try:
uuid.UUID(config['cmid'])
except:
logging.error("Bad CMID. Exiting...")
sys.exit()
if config['machineName'] is not None:
if len(config['machineName']) < 2 or len(config['machineName']) > 63:
logging.error("machineName must be between 2 and 63 characters in length.")
sys.exit()
def updateConfig():
if config['mode'] == 'WindowsVista':
config['RequiredClientCount'] = 25
config['KMSProtocolMajorVersion'] = 4
config['KMSProtocolMinorVersion'] = 0
config['KMSClientLicenseStatus'] = 2
config['KMSClientAppID'] = "55c92734-d682-4d71-983e-d6ec3f16059f"
config['KMSClientSkuID'] = "cfd8ff08-c0d7-452b-9f60-ef5c70c32094"
config['KMSClientKMSCountedID'] = "212a64dc-43b1-4d3d-a30c-2fc69d2095c6"
elif config['mode'] == 'Windows7':
config['RequiredClientCount'] = 25
config['KMSProtocolMajorVersion'] = 4
config['KMSProtocolMinorVersion'] = 0
config['KMSClientLicenseStatus'] = 2
config['KMSClientAppID'] = "55c92734-d682-4d71-983e-d6ec3f16059f"
config['KMSClientSkuID'] = "ae2ee509-1b34-41c0-acb7-6d4650168915"
config['KMSClientKMSCountedID'] = "7fde5219-fbfa-484a-82c9-34d1ad53e856"
elif config['mode'] == 'Windows8':
config['RequiredClientCount'] = 25
config['KMSProtocolMajorVersion'] = 5
config['KMSProtocolMinorVersion'] = 0
config['KMSClientLicenseStatus'] = 2
config['KMSClientAppID'] = "55c92734-d682-4d71-983e-d6ec3f16059f"
config['KMSClientSkuID'] = "458e1bec-837a-45f6-b9d5-925ed5d299de"
config['KMSClientKMSCountedID'] = "3c40b358-5948-45af-923b-53d21fcc7e79"
elif config['mode'] == 'Windows81':
config['RequiredClientCount'] = 25
config['KMSProtocolMajorVersion'] = 6
config['KMSProtocolMinorVersion'] = 0
config['KMSClientLicenseStatus'] = 2
config['KMSClientAppID'] = "55c92734-d682-4d71-983e-d6ec3f16059f"
config['KMSClientSkuID'] = "81671aaf-79d1-4eb1-b004-8cbbe173afea"
config['KMSClientKMSCountedID'] = "cb8fc780-2c05-495a-9710-85afffc904d7"
elif config['mode'] == 'Windows10':
config['RequiredClientCount'] = 25
config['KMSProtocolMajorVersion'] = 6
config['KMSProtocolMinorVersion'] = 0
config['KMSClientLicenseStatus'] = 2
config['KMSClientAppID'] = "55c92734-d682-4d71-983e-d6ec3f16059f"
config['KMSClientSkuID'] = "73111121-5638-40f6-bc11-f1d7b0d64300"
config['KMSClientKMSCountedID'] = "58e2134f-8e11-4d17-9cb2-91069c151148"
elif config['mode'] == 'Office2010':
config['RequiredClientCount'] = 5
config['KMSProtocolMajorVersion'] = 4
config['KMSProtocolMinorVersion'] = 0
config['KMSClientLicenseStatus'] = 2
config['KMSClientAppID'] = "59a52881-a989-479d-af46-f275c6370663"
config['KMSClientSkuID'] = "6f327760-8c5c-417c-9b61-836a98287e0c"
config['KMSClientKMSCountedID'] = "e85af946-2e25-47b7-83e1-bebcebeac611"
elif config['mode'] == 'Office2013':
config['RequiredClientCount'] = 5
config['KMSProtocolMajorVersion'] = 5
config['KMSProtocolMinorVersion'] = 0
config['KMSClientLicenseStatus'] = 2
config['KMSClientAppID'] = "0ff1ce15-a989-479d-af46-f275c6370663"
config['KMSClientSkuID'] = "b322da9c-a2e2-4058-9e4e-f59a6970bd69"
config['KMSClientKMSCountedID'] = "e6a6f1bf-9d40-40c3-aa9f-c77ba21578c0"
elif config['mode'] == 'Office2016':
config['RequiredClientCount'] = 5
config['KMSProtocolMajorVersion'] = 6
config['KMSProtocolMinorVersion'] = 0
config['KMSClientLicenseStatus'] = 2
config['KMSClientAppID'] = "0ff1ce15-a989-479d-af46-f275c6370663"
config['KMSClientSkuID'] = "d450596f-894d-49e0-966a-fd39ed4c4c64"
config['KMSClientKMSCountedID'] = "85b5f61b-320b-4be3-814a-b76b2bfafc82"
def createKmsRequestBase():
requestDict = kmsBase.kmsRequestStruct()
requestDict['versionMinor'] = config['KMSProtocolMinorVersion']
requestDict['versionMajor'] = config['KMSProtocolMajorVersion']
requestDict['isClientVm'] = 0
requestDict['licenseStatus'] = config['KMSClientLicenseStatus']
requestDict['graceTime'] = 43200
requestDict['applicationId'] = UUID(uuid.UUID(config['KMSClientAppID']).bytes_le)
requestDict['skuId'] = UUID(uuid.UUID(config['KMSClientSkuID']).bytes_le)
requestDict['kmsCountedId'] = UUID(uuid.UUID(config['KMSClientKMSCountedID']).bytes_le)
requestDict['clientMachineId'] = UUID(uuid.UUID(config['cmid']).bytes_le if (config['cmid'] is not None) else uuid.uuid4().bytes_le)
requestDict['previousClientMachineId'] = '\0' * 16 #requestDict['clientMachineId'] # I'm pretty sure this is supposed to be a null UUID.
requestDict['requiredClientCount'] = config['RequiredClientCount']
requestDict['requestTime'] = filetimes.dt_to_filetime(datetime.datetime.utcnow())
requestDict['machineName'] = (config['machineName'] if (config['machineName'] is not None) else
''.join(random.choice(string.ascii_letters + string.digits) for i in range(random.randint(2,63)))).encode('utf-16le')
requestDict['mnPad'] = '\0'.encode('utf-16le') * (63 - len(requestDict['machineName'].decode('utf-16le')))
# Debug Stuff
shell_message(nshell = 9)
requestDict = byterize(requestDict)
logging.debug("Request Base Dictionary: \n%s\n" % justify(requestDict.dump(print_to_stdout = False)))
return requestDict
def createKmsRequest():
# Update the call ID
config['call_id'] += 1
# KMS Protocol Major Version
if config['KMSProtocolMajorVersion'] == 4:
handler = kmsRequestV4(None, config)
elif config['KMSProtocolMajorVersion'] == 5:
handler = kmsRequestV5(None, config)
elif config['KMSProtocolMajorVersion'] == 6:
handler = kmsRequestV6(None, config)
else:
return None
requestBase = createKmsRequestBase()
return handler.generateRequest(requestBase)
def readKmsResponse(data, request, config):
if config['KMSProtocolMajorVersion'] == 4:
logging.info("Received V4 response")
response = readKmsResponseV4(data, request)
elif config['KMSProtocolMajorVersion'] == 5:
logging.info("Received V5 response")
response = readKmsResponseV5(data)
elif config['KMSProtocolMajorVersion'] == 6:
logging.info("Received V6 response")
response = readKmsResponseV6(data)
else:
logging.info("Unhandled response version: %d.%d" % (config['KMSProtocolMajorVersion'], config['KMSProtocolMinorVersion']))
logging.info("I'm not even sure how this happened...")
return response
def readKmsResponseV4(data, request):
response = kmsRequestV4.ResponseV4(data)
hashed = kmsRequestV4(data, config).generateHash(bytearray(str(response['response']).encode('latin-1'))) #*2to3*
if hashed.decode('latin-1') == response['hash']:
logging.info("Response Hash has expected value !!")
return response
def readKmsResponseV5(data):
response = kmsRequestV5.ResponseV5(data)
decrypted = kmsRequestV5(data, config).decryptResponse(response)
return decrypted
def readKmsResponseV6(data):
response = kmsRequestV6.ResponseV5(data)
decrypted = kmsRequestV6(data, config).decryptResponse(response)
message = decrypted['message']
return message
if __name__ == "__main__":
main()

765
py3-kms/dcerpc.py Normal file
View File

@ -0,0 +1,765 @@
#!/usr/bin/env python3
# Copyright (c) 2003-2014 CORE Security Technologies
#
# This software is provided under under a slightly modified version
# of the Apache Software License. See the accompanying LICENSE file
# for more information.
#
# Description:
# Partial C706.pdf + [MS-RPCE] implementation
#
# Best way to learn how to use these calls is to grab the protocol standard
# so you understand what the call does, and then read the test case located
# at https://github.com/CoreSecurity/impacket/tree/master/impacket/testcases/SMB_RPC
#
# ToDo:
# [ ] Take out all the security provider stuff out of here (e.g. RPC_C_AUTHN_WINNT)
# and put it elsewhere. This will make the coder cleaner and easier to add
# more SSP (e.g. NETLOGON)
#
"""
Stripped down version of `https://github.com/CoreSecurity/impacket/blob/master/impacket/dcerpc/v5/rpcrt.py`,
modified for Python3.
"""
from structure import Structure, pack, unpack
# MS/RPC Constants
MSRPC_REQUEST = 0x00
MSRPC_PING = 0x01
MSRPC_RESPONSE = 0x02
MSRPC_FAULT = 0x03
MSRPC_WORKING = 0x04
MSRPC_NOCALL = 0x05
MSRPC_REJECT = 0x06
MSRPC_ACK = 0x07
MSRPC_CL_CANCEL = 0x08
MSRPC_FACK = 0x09
MSRPC_CANCELACK = 0x0A
MSRPC_BIND = 0x0B
MSRPC_BINDACK = 0x0C
MSRPC_BINDNAK = 0x0D
MSRPC_ALTERCTX = 0x0E
MSRPC_ALTERCTX_R= 0x0F
MSRPC_AUTH3 = 0x10
MSRPC_SHUTDOWN = 0x11
MSRPC_CO_CANCEL = 0x12
MSRPC_ORPHANED = 0x13
# MS/RPC Packet Flags
MSRPC_FIRSTFRAG = 0x01
MSRPC_LASTFRAG = 0x02
# For PDU types bind, bind_ack, alter_context, and
# alter_context_resp, this flag MUST be interpreted as PFC_SUPPORT_HEADER_SIGN
MSRPC_SUPPORT_SIGN = 0x04
#For the
#remaining PDU types, this flag MUST be interpreted as PFC_PENDING_CANCEL.
MSRPC_PENDING_CANCEL= 0x04
MSRPC_NOTAFRAG = 0x04
MSRPC_RECRESPOND = 0x08
MSRPC_NOMULTIPLEX = 0x10
MSRPC_NOTFORIDEMP = 0x20
MSRPC_NOTFORBCAST = 0x40
MSRPC_NOUUID = 0x80
# Auth Types - Security Providers
RPC_C_AUTHN_NONE = 0x00
RPC_C_AUTHN_GSS_NEGOTIATE = 0x09
RPC_C_AUTHN_WINNT = 0x0A
RPC_C_AUTHN_GSS_SCHANNEL = 0x0E
RPC_C_AUTHN_GSS_KERBEROS = 0x10
RPC_C_AUTHN_NETLOGON = 0x44
RPC_C_AUTHN_DEFAULT = 0xFF
# Auth Levels
RPC_C_AUTHN_LEVEL_NONE = 1
RPC_C_AUTHN_LEVEL_CONNECT = 2
RPC_C_AUTHN_LEVEL_CALL = 3
RPC_C_AUTHN_LEVEL_PKT = 4
RPC_C_AUTHN_LEVEL_PKT_INTEGRITY = 5
RPC_C_AUTHN_LEVEL_PKT_PRIVACY = 6
#Reasons for rejection of a context element, included in bind_ack result reason
rpc_provider_reason = {
0 : 'reason_not_specified',
1 : 'abstract_syntax_not_supported',
2 : 'proposed_transfer_syntaxes_not_supported',
3 : 'local_limit_exceeded',
4 : 'protocol_version_not_specified',
8 : 'authentication_type_not_recognized',
9 : 'invalid_checksum'
}
MSRPC_CONT_RESULT_ACCEPT = 0
MSRPC_CONT_RESULT_USER_REJECT = 1
MSRPC_CONT_RESULT_PROV_REJECT = 2
#Results of a presentation context negotiation
rpc_cont_def_result = {
0 : 'acceptance',
1 : 'user_rejection',
2 : 'provider_rejection'
}
#status codes, references:
#http://msdn.microsoft.com/library/default.asp?url=/library/en-us/rpc/rpc/rpc_return_values.asp
#http://msdn.microsoft.com/library/default.asp?url=/library/en-us/randz/protocol/common_return_values.asp
#winerror.h
#http://www.opengroup.org/onlinepubs/9629399/apdxn.htm
#*2to3* 0x00000005L -> 0x00000005.....
rpc_status_codes = {
0x00000005 : 'rpc_s_access_denied',
0x00000008 : 'Authentication type not recognized',
0x000006D8 : 'rpc_fault_cant_perform',
0x000006C6 : 'rpc_x_invalid_bound', # the arrays bound are invalid
0x000006E4 : 'rpc_s_cannot_support: The requested operation is not supported.', # some operation is not supported
0x000006F7 : 'rpc_x_bad_stub_data', # the stub data is invalid, doesn't match with the IDL definition
0x1C010001 : 'nca_s_comm_failure', # unable to get response from server:
0x1C010002 : 'nca_s_op_rng_error', # bad operation number in call
0x1C010003 : 'nca_s_unk_if', # unknown interface
0x1C010006 : 'nca_s_wrong_boot_time', # client passed server wrong server boot time
0x1C010009 : 'nca_s_you_crashed', # a restarted server called back a client
0x1C01000B : 'nca_s_proto_error', # someone messed up the protocol
0x1C010013 : 'nca_s_out_args_too_big ', # output args too big
0x1C010014 : 'nca_s_server_too_busy', # server is too busy to handle call
0x1C010015 : 'nca_s_fault_string_too_long', # string argument longer than declared max len
0x1C010017 : 'nca_s_unsupported_type ', # no implementation of generic operation for object
0x1C000001 : 'nca_s_fault_int_div_by_zero',
0x1C000002 : 'nca_s_fault_addr_error ',
0x1C000003 : 'nca_s_fault_fp_div_zero',
0x1C000004 : 'nca_s_fault_fp_underflow',
0x1C000005 : 'nca_s_fault_fp_overflow',
0x1C000006 : 'nca_s_fault_invalid_tag',
0x1C000007 : 'nca_s_fault_invalid_bound ',
0x1C000008 : 'nca_s_rpc_version_mismatch',
0x1C000009 : 'nca_s_unspec_reject ',
0x1C00000A : 'nca_s_bad_actid',
0x1C00000B : 'nca_s_who_are_you_failed',
0x1C00000C : 'nca_s_manager_not_entered ',
0x1C00000D : 'nca_s_fault_cancel',
0x1C00000E : 'nca_s_fault_ill_inst',
0x1C00000F : 'nca_s_fault_fp_error',
0x1C000010 : 'nca_s_fault_int_overflow',
0x1C000012 : 'nca_s_fault_unspec',
0x1C000013 : 'nca_s_fault_remote_comm_failure ',
0x1C000014 : 'nca_s_fault_pipe_empty ',
0x1C000015 : 'nca_s_fault_pipe_closed',
0x1C000016 : 'nca_s_fault_pipe_order ',
0x1C000017 : 'nca_s_fault_pipe_discipline',
0x1C000018 : 'nca_s_fault_pipe_comm_error',
0x1C000019 : 'nca_s_fault_pipe_memory',
0x1C00001A : 'nca_s_fault_context_mismatch ',
0x1C00001B : 'nca_s_fault_remote_no_memory ',
0x1C00001C : 'nca_s_invalid_pres_context_id',
0x1C00001D : 'nca_s_unsupported_authn_level',
0x1C00001F : 'nca_s_invalid_checksum ',
0x1C000020 : 'nca_s_invalid_crc',
0x1C000021 : 'nca_s_fault_user_defined',
0x1C000022 : 'nca_s_fault_tx_open_failed',
0x1C000023 : 'nca_s_fault_codeset_conv_error',
0x1C000024 : 'nca_s_fault_object_not_found ',
0x1C000025 : 'nca_s_fault_no_client_stub',
0x16c9a000 : "rpc_s_mod",
0x16c9a001 : "rpc_s_op_rng_error",
0x16c9a002 : "rpc_s_cant_create_socket",
0x16c9a003 : "rpc_s_cant_bind_socket",
0x16c9a004 : "rpc_s_not_in_call",
0x16c9a005 : "rpc_s_no_port",
0x16c9a006 : "rpc_s_wrong_boot_time",
0x16c9a007 : "rpc_s_too_many_sockets",
0x16c9a008 : "rpc_s_illegal_register",
0x16c9a009 : "rpc_s_cant_recv",
0x16c9a00a : "rpc_s_bad_pkt",
0x16c9a00b : "rpc_s_unbound_handle",
0x16c9a00c : "rpc_s_addr_in_use",
0x16c9a00d : "rpc_s_in_args_too_big",
0x16c9a00e : "rpc_s_string_too_long",
0x16c9a00f : "rpc_s_too_many_objects",
0x16c9a010 : "rpc_s_binding_has_no_auth",
0x16c9a011 : "rpc_s_unknown_authn_service",
0x16c9a012 : "rpc_s_no_memory",
0x16c9a013 : "rpc_s_cant_nmalloc",
0x16c9a014 : "rpc_s_call_faulted",
0x16c9a015 : "rpc_s_call_failed",
0x16c9a016 : "rpc_s_comm_failure",
0x16c9a017 : "rpc_s_rpcd_comm_failure",
0x16c9a018 : "rpc_s_illegal_family_rebind",
0x16c9a019 : "rpc_s_invalid_handle",
0x16c9a01a : "rpc_s_coding_error",
0x16c9a01b : "rpc_s_object_not_found",
0x16c9a01c : "rpc_s_cthread_not_found",
0x16c9a01d : "rpc_s_invalid_binding",
0x16c9a01e : "rpc_s_already_registered",
0x16c9a01f : "rpc_s_endpoint_not_found",
0x16c9a020 : "rpc_s_invalid_rpc_protseq",
0x16c9a021 : "rpc_s_desc_not_registered",
0x16c9a022 : "rpc_s_already_listening",
0x16c9a023 : "rpc_s_no_protseqs",
0x16c9a024 : "rpc_s_no_protseqs_registered",
0x16c9a025 : "rpc_s_no_bindings",
0x16c9a026 : "rpc_s_max_descs_exceeded",
0x16c9a027 : "rpc_s_no_interfaces",
0x16c9a028 : "rpc_s_invalid_timeout",
0x16c9a029 : "rpc_s_cant_inq_socket",
0x16c9a02a : "rpc_s_invalid_naf_id",
0x16c9a02b : "rpc_s_inval_net_addr",
0x16c9a02c : "rpc_s_unknown_if",
0x16c9a02d : "rpc_s_unsupported_type",
0x16c9a02e : "rpc_s_invalid_call_opt",
0x16c9a02f : "rpc_s_no_fault",
0x16c9a030 : "rpc_s_cancel_timeout",
0x16c9a031 : "rpc_s_call_cancelled",
0x16c9a032 : "rpc_s_invalid_call_handle",
0x16c9a033 : "rpc_s_cannot_alloc_assoc",
0x16c9a034 : "rpc_s_cannot_connect",
0x16c9a035 : "rpc_s_connection_aborted",
0x16c9a036 : "rpc_s_connection_closed",
0x16c9a037 : "rpc_s_cannot_accept",
0x16c9a038 : "rpc_s_assoc_grp_not_found",
0x16c9a039 : "rpc_s_stub_interface_error",
0x16c9a03a : "rpc_s_invalid_object",
0x16c9a03b : "rpc_s_invalid_type",
0x16c9a03c : "rpc_s_invalid_if_opnum",
0x16c9a03d : "rpc_s_different_server_instance",
0x16c9a03e : "rpc_s_protocol_error",
0x16c9a03f : "rpc_s_cant_recvmsg",
0x16c9a040 : "rpc_s_invalid_string_binding",
0x16c9a041 : "rpc_s_connect_timed_out",
0x16c9a042 : "rpc_s_connect_rejected",
0x16c9a043 : "rpc_s_network_unreachable",
0x16c9a044 : "rpc_s_connect_no_resources",
0x16c9a045 : "rpc_s_rem_network_shutdown",
0x16c9a046 : "rpc_s_too_many_rem_connects",
0x16c9a047 : "rpc_s_no_rem_endpoint",
0x16c9a048 : "rpc_s_rem_host_down",
0x16c9a049 : "rpc_s_host_unreachable",
0x16c9a04a : "rpc_s_access_control_info_inv",
0x16c9a04b : "rpc_s_loc_connect_aborted",
0x16c9a04c : "rpc_s_connect_closed_by_rem",
0x16c9a04d : "rpc_s_rem_host_crashed",
0x16c9a04e : "rpc_s_invalid_endpoint_format",
0x16c9a04f : "rpc_s_unknown_status_code",
0x16c9a050 : "rpc_s_unknown_mgr_type",
0x16c9a051 : "rpc_s_assoc_creation_failed",
0x16c9a052 : "rpc_s_assoc_grp_max_exceeded",
0x16c9a053 : "rpc_s_assoc_grp_alloc_failed",
0x16c9a054 : "rpc_s_sm_invalid_state",
0x16c9a055 : "rpc_s_assoc_req_rejected",
0x16c9a056 : "rpc_s_assoc_shutdown",
0x16c9a057 : "rpc_s_tsyntaxes_unsupported",
0x16c9a058 : "rpc_s_context_id_not_found",
0x16c9a059 : "rpc_s_cant_listen_socket",
0x16c9a05a : "rpc_s_no_addrs",
0x16c9a05b : "rpc_s_cant_getpeername",
0x16c9a05c : "rpc_s_cant_get_if_id",
0x16c9a05d : "rpc_s_protseq_not_supported",
0x16c9a05e : "rpc_s_call_orphaned",
0x16c9a05f : "rpc_s_who_are_you_failed",
0x16c9a060 : "rpc_s_unknown_reject",
0x16c9a061 : "rpc_s_type_already_registered",
0x16c9a062 : "rpc_s_stop_listening_disabled",
0x16c9a063 : "rpc_s_invalid_arg",
0x16c9a064 : "rpc_s_not_supported",
0x16c9a065 : "rpc_s_wrong_kind_of_binding",
0x16c9a066 : "rpc_s_authn_authz_mismatch",
0x16c9a067 : "rpc_s_call_queued",
0x16c9a068 : "rpc_s_cannot_set_nodelay",
0x16c9a069 : "rpc_s_not_rpc_tower",
0x16c9a06a : "rpc_s_invalid_rpc_protid",
0x16c9a06b : "rpc_s_invalid_rpc_floor",
0x16c9a06c : "rpc_s_call_timeout",
0x16c9a06d : "rpc_s_mgmt_op_disallowed",
0x16c9a06e : "rpc_s_manager_not_entered",
0x16c9a06f : "rpc_s_calls_too_large_for_wk_ep",
0x16c9a070 : "rpc_s_server_too_busy",
0x16c9a071 : "rpc_s_prot_version_mismatch",
0x16c9a072 : "rpc_s_rpc_prot_version_mismatch",
0x16c9a073 : "rpc_s_ss_no_import_cursor",
0x16c9a074 : "rpc_s_fault_addr_error",
0x16c9a075 : "rpc_s_fault_context_mismatch",
0x16c9a076 : "rpc_s_fault_fp_div_by_zero",
0x16c9a077 : "rpc_s_fault_fp_error",
0x16c9a078 : "rpc_s_fault_fp_overflow",
0x16c9a079 : "rpc_s_fault_fp_underflow",
0x16c9a07a : "rpc_s_fault_ill_inst",
0x16c9a07b : "rpc_s_fault_int_div_by_zero",
0x16c9a07c : "rpc_s_fault_int_overflow",
0x16c9a07d : "rpc_s_fault_invalid_bound",
0x16c9a07e : "rpc_s_fault_invalid_tag",
0x16c9a07f : "rpc_s_fault_pipe_closed",
0x16c9a080 : "rpc_s_fault_pipe_comm_error",
0x16c9a081 : "rpc_s_fault_pipe_discipline",
0x16c9a082 : "rpc_s_fault_pipe_empty",
0x16c9a083 : "rpc_s_fault_pipe_memory",
0x16c9a084 : "rpc_s_fault_pipe_order",
0x16c9a085 : "rpc_s_fault_remote_comm_failure",
0x16c9a086 : "rpc_s_fault_remote_no_memory",
0x16c9a087 : "rpc_s_fault_unspec",
0x16c9a088 : "uuid_s_bad_version",
0x16c9a089 : "uuid_s_socket_failure",
0x16c9a08a : "uuid_s_getconf_failure",
0x16c9a08b : "uuid_s_no_address",
0x16c9a08c : "uuid_s_overrun",
0x16c9a08d : "uuid_s_internal_error",
0x16c9a08e : "uuid_s_coding_error",
0x16c9a08f : "uuid_s_invalid_string_uuid",
0x16c9a090 : "uuid_s_no_memory",
0x16c9a091 : "rpc_s_no_more_entries",
0x16c9a092 : "rpc_s_unknown_ns_error",
0x16c9a093 : "rpc_s_name_service_unavailable",
0x16c9a094 : "rpc_s_incomplete_name",
0x16c9a095 : "rpc_s_group_not_found",
0x16c9a096 : "rpc_s_invalid_name_syntax",
0x16c9a097 : "rpc_s_no_more_members",
0x16c9a098 : "rpc_s_no_more_interfaces",
0x16c9a099 : "rpc_s_invalid_name_service",
0x16c9a09a : "rpc_s_no_name_mapping",
0x16c9a09b : "rpc_s_profile_not_found",
0x16c9a09c : "rpc_s_not_found",
0x16c9a09d : "rpc_s_no_updates",
0x16c9a09e : "rpc_s_update_failed",
0x16c9a09f : "rpc_s_no_match_exported",
0x16c9a0a0 : "rpc_s_entry_not_found",
0x16c9a0a1 : "rpc_s_invalid_inquiry_context",
0x16c9a0a2 : "rpc_s_interface_not_found",
0x16c9a0a3 : "rpc_s_group_member_not_found",
0x16c9a0a4 : "rpc_s_entry_already_exists",
0x16c9a0a5 : "rpc_s_nsinit_failure",
0x16c9a0a6 : "rpc_s_unsupported_name_syntax",
0x16c9a0a7 : "rpc_s_no_more_elements",
0x16c9a0a8 : "rpc_s_no_ns_permission",
0x16c9a0a9 : "rpc_s_invalid_inquiry_type",
0x16c9a0aa : "rpc_s_profile_element_not_found",
0x16c9a0ab : "rpc_s_profile_element_replaced",
0x16c9a0ac : "rpc_s_import_already_done",
0x16c9a0ad : "rpc_s_database_busy",
0x16c9a0ae : "rpc_s_invalid_import_context",
0x16c9a0af : "rpc_s_uuid_set_not_found",
0x16c9a0b0 : "rpc_s_uuid_member_not_found",
0x16c9a0b1 : "rpc_s_no_interfaces_exported",
0x16c9a0b2 : "rpc_s_tower_set_not_found",
0x16c9a0b3 : "rpc_s_tower_member_not_found",
0x16c9a0b4 : "rpc_s_obj_uuid_not_found",
0x16c9a0b5 : "rpc_s_no_more_bindings",
0x16c9a0b6 : "rpc_s_invalid_priority",
0x16c9a0b7 : "rpc_s_not_rpc_entry",
0x16c9a0b8 : "rpc_s_invalid_lookup_context",
0x16c9a0b9 : "rpc_s_binding_vector_full",
0x16c9a0ba : "rpc_s_cycle_detected",
0x16c9a0bb : "rpc_s_nothing_to_export",
0x16c9a0bc : "rpc_s_nothing_to_unexport",
0x16c9a0bd : "rpc_s_invalid_vers_option",
0x16c9a0be : "rpc_s_no_rpc_data",
0x16c9a0bf : "rpc_s_mbr_picked",
0x16c9a0c0 : "rpc_s_not_all_objs_unexported",
0x16c9a0c1 : "rpc_s_no_entry_name",
0x16c9a0c2 : "rpc_s_priority_group_done",
0x16c9a0c3 : "rpc_s_partial_results",
0x16c9a0c4 : "rpc_s_no_env_setup",
0x16c9a0c5 : "twr_s_unknown_sa",
0x16c9a0c6 : "twr_s_unknown_tower",
0x16c9a0c7 : "twr_s_not_implemented",
0x16c9a0c8 : "rpc_s_max_calls_too_small",
0x16c9a0c9 : "rpc_s_cthread_create_failed",
0x16c9a0ca : "rpc_s_cthread_pool_exists",
0x16c9a0cb : "rpc_s_cthread_no_such_pool",
0x16c9a0cc : "rpc_s_cthread_invoke_disabled",
0x16c9a0cd : "ept_s_cant_perform_op",
0x16c9a0ce : "ept_s_no_memory",
0x16c9a0cf : "ept_s_database_invalid",
0x16c9a0d0 : "ept_s_cant_create",
0x16c9a0d1 : "ept_s_cant_access",
0x16c9a0d2 : "ept_s_database_already_open",
0x16c9a0d3 : "ept_s_invalid_entry",
0x16c9a0d4 : "ept_s_update_failed",
0x16c9a0d5 : "ept_s_invalid_context",
0x16c9a0d6 : "ept_s_not_registered",
0x16c9a0d7 : "ept_s_server_unavailable",
0x16c9a0d8 : "rpc_s_underspecified_name",
0x16c9a0d9 : "rpc_s_invalid_ns_handle",
0x16c9a0da : "rpc_s_unknown_error",
0x16c9a0db : "rpc_s_ss_char_trans_open_fail",
0x16c9a0dc : "rpc_s_ss_char_trans_short_file",
0x16c9a0dd : "rpc_s_ss_context_damaged",
0x16c9a0de : "rpc_s_ss_in_null_context",
0x16c9a0df : "rpc_s_socket_failure",
0x16c9a0e0 : "rpc_s_unsupported_protect_level",
0x16c9a0e1 : "rpc_s_invalid_checksum",
0x16c9a0e2 : "rpc_s_invalid_credentials",
0x16c9a0e3 : "rpc_s_credentials_too_large",
0x16c9a0e4 : "rpc_s_call_id_not_found",
0x16c9a0e5 : "rpc_s_key_id_not_found",
0x16c9a0e6 : "rpc_s_auth_bad_integrity",
0x16c9a0e7 : "rpc_s_auth_tkt_expired",
0x16c9a0e8 : "rpc_s_auth_tkt_nyv",
0x16c9a0e9 : "rpc_s_auth_repeat",
0x16c9a0ea : "rpc_s_auth_not_us",
0x16c9a0eb : "rpc_s_auth_badmatch",
0x16c9a0ec : "rpc_s_auth_skew",
0x16c9a0ed : "rpc_s_auth_badaddr",
0x16c9a0ee : "rpc_s_auth_badversion",
0x16c9a0ef : "rpc_s_auth_msg_type",
0x16c9a0f0 : "rpc_s_auth_modified",
0x16c9a0f1 : "rpc_s_auth_badorder",
0x16c9a0f2 : "rpc_s_auth_badkeyver",
0x16c9a0f3 : "rpc_s_auth_nokey",
0x16c9a0f4 : "rpc_s_auth_mut_fail",
0x16c9a0f5 : "rpc_s_auth_baddirection",
0x16c9a0f6 : "rpc_s_auth_method",
0x16c9a0f7 : "rpc_s_auth_badseq",
0x16c9a0f8 : "rpc_s_auth_inapp_cksum",
0x16c9a0f9 : "rpc_s_auth_field_toolong",
0x16c9a0fa : "rpc_s_invalid_crc",
0x16c9a0fb : "rpc_s_binding_incomplete",
0x16c9a0fc : "rpc_s_key_func_not_allowed",
0x16c9a0fd : "rpc_s_unknown_stub_rtl_if_vers",
0x16c9a0fe : "rpc_s_unknown_ifspec_vers",
0x16c9a0ff : "rpc_s_proto_unsupp_by_auth",
0x16c9a100 : "rpc_s_authn_challenge_malformed",
0x16c9a101 : "rpc_s_protect_level_mismatch",
0x16c9a102 : "rpc_s_no_mepv",
0x16c9a103 : "rpc_s_stub_protocol_error",
0x16c9a104 : "rpc_s_class_version_mismatch",
0x16c9a105 : "rpc_s_helper_not_running",
0x16c9a106 : "rpc_s_helper_short_read",
0x16c9a107 : "rpc_s_helper_catatonic",
0x16c9a108 : "rpc_s_helper_aborted",
0x16c9a109 : "rpc_s_not_in_kernel",
0x16c9a10a : "rpc_s_helper_wrong_user",
0x16c9a10b : "rpc_s_helper_overflow",
0x16c9a10c : "rpc_s_dg_need_way_auth",
0x16c9a10d : "rpc_s_unsupported_auth_subtype",
0x16c9a10e : "rpc_s_wrong_pickle_type",
0x16c9a10f : "rpc_s_not_listening",
0x16c9a110 : "rpc_s_ss_bad_buffer",
0x16c9a111 : "rpc_s_ss_bad_es_action",
0x16c9a112 : "rpc_s_ss_wrong_es_version",
0x16c9a113 : "rpc_s_fault_user_defined",
0x16c9a114 : "rpc_s_ss_incompatible_codesets",
0x16c9a115 : "rpc_s_tx_not_in_transaction",
0x16c9a116 : "rpc_s_tx_open_failed",
0x16c9a117 : "rpc_s_partial_credentials",
0x16c9a118 : "rpc_s_ss_invalid_codeset_tag",
0x16c9a119 : "rpc_s_mgmt_bad_type",
0x16c9a11a : "rpc_s_ss_invalid_char_input",
0x16c9a11b : "rpc_s_ss_short_conv_buffer",
0x16c9a11c : "rpc_s_ss_iconv_error",
0x16c9a11d : "rpc_s_ss_no_compat_codeset",
0x16c9a11e : "rpc_s_ss_no_compat_charsets",
0x16c9a11f : "dce_cs_c_ok",
0x16c9a120 : "dce_cs_c_unknown",
0x16c9a121 : "dce_cs_c_notfound",
0x16c9a122 : "dce_cs_c_cannot_open_file",
0x16c9a123 : "dce_cs_c_cannot_read_file",
0x16c9a124 : "dce_cs_c_cannot_allocate_memory",
0x16c9a125 : "rpc_s_ss_cleanup_failed",
0x16c9a126 : "rpc_svc_desc_general",
0x16c9a127 : "rpc_svc_desc_mutex",
0x16c9a128 : "rpc_svc_desc_xmit",
0x16c9a129 : "rpc_svc_desc_recv",
0x16c9a12a : "rpc_svc_desc_dg_state",
0x16c9a12b : "rpc_svc_desc_cancel",
0x16c9a12c : "rpc_svc_desc_orphan",
0x16c9a12d : "rpc_svc_desc_cn_state",
0x16c9a12e : "rpc_svc_desc_cn_pkt",
0x16c9a12f : "rpc_svc_desc_pkt_quotas",
0x16c9a130 : "rpc_svc_desc_auth",
0x16c9a131 : "rpc_svc_desc_source",
0x16c9a132 : "rpc_svc_desc_stats",
0x16c9a133 : "rpc_svc_desc_mem",
0x16c9a134 : "rpc_svc_desc_mem_type",
0x16c9a135 : "rpc_svc_desc_dg_pktlog",
0x16c9a136 : "rpc_svc_desc_thread_id",
0x16c9a137 : "rpc_svc_desc_timestamp",
0x16c9a138 : "rpc_svc_desc_cn_errors",
0x16c9a139 : "rpc_svc_desc_conv_thread",
0x16c9a13a : "rpc_svc_desc_pid",
0x16c9a13b : "rpc_svc_desc_atfork",
0x16c9a13c : "rpc_svc_desc_cma_thread",
0x16c9a13d : "rpc_svc_desc_inherit",
0x16c9a13e : "rpc_svc_desc_dg_sockets",
0x16c9a13f : "rpc_svc_desc_timer",
0x16c9a140 : "rpc_svc_desc_threads",
0x16c9a141 : "rpc_svc_desc_server_call",
0x16c9a142 : "rpc_svc_desc_nsi",
0x16c9a143 : "rpc_svc_desc_dg_pkt",
0x16c9a144 : "rpc_m_cn_ill_state_trans_sa",
0x16c9a145 : "rpc_m_cn_ill_state_trans_ca",
0x16c9a146 : "rpc_m_cn_ill_state_trans_sg",
0x16c9a147 : "rpc_m_cn_ill_state_trans_cg",
0x16c9a148 : "rpc_m_cn_ill_state_trans_sr",
0x16c9a149 : "rpc_m_cn_ill_state_trans_cr",
0x16c9a14a : "rpc_m_bad_pkt_type",
0x16c9a14b : "rpc_m_prot_mismatch",
0x16c9a14c : "rpc_m_frag_toobig",
0x16c9a14d : "rpc_m_unsupp_stub_rtl_if",
0x16c9a14e : "rpc_m_unhandled_callstate",
0x16c9a14f : "rpc_m_call_failed",
0x16c9a150 : "rpc_m_call_failed_no_status",
0x16c9a151 : "rpc_m_call_failed_errno",
0x16c9a152 : "rpc_m_call_failed_s",
0x16c9a153 : "rpc_m_call_failed_c",
0x16c9a154 : "rpc_m_errmsg_toobig",
0x16c9a155 : "rpc_m_invalid_srchattr",
0x16c9a156 : "rpc_m_nts_not_found",
0x16c9a157 : "rpc_m_invalid_accbytcnt",
0x16c9a158 : "rpc_m_pre_v2_ifspec",
0x16c9a159 : "rpc_m_unk_ifspec",
0x16c9a15a : "rpc_m_recvbuf_toosmall",
0x16c9a15b : "rpc_m_unalign_authtrl",
0x16c9a15c : "rpc_m_unexpected_exc",
0x16c9a15d : "rpc_m_no_stub_data",
0x16c9a15e : "rpc_m_eventlist_full",
0x16c9a15f : "rpc_m_unk_sock_type",
0x16c9a160 : "rpc_m_unimp_call",
0x16c9a161 : "rpc_m_invalid_seqnum",
0x16c9a162 : "rpc_m_cant_create_uuid",
0x16c9a163 : "rpc_m_pre_v2_ss",
0x16c9a164 : "rpc_m_dgpkt_pool_corrupt",
0x16c9a165 : "rpc_m_dgpkt_bad_free",
0x16c9a166 : "rpc_m_lookaside_corrupt",
0x16c9a167 : "rpc_m_alloc_fail",
0x16c9a168 : "rpc_m_realloc_fail",
0x16c9a169 : "rpc_m_cant_open_file",
0x16c9a16a : "rpc_m_cant_read_addr",
0x16c9a16b : "rpc_svc_desc_libidl",
0x16c9a16c : "rpc_m_ctxrundown_nomem",
0x16c9a16d : "rpc_m_ctxrundown_exc",
0x16c9a16e : "rpc_s_fault_codeset_conv_error",
0x16c9a16f : "rpc_s_no_call_active",
0x16c9a170 : "rpc_s_cannot_support",
0x16c9a171 : "rpc_s_no_context_available",
}
class Exception(Exception):
pass
##class DCERPCException(Exception):
## def __init__( self, error_code):
## Exception.__init__(self)
## self.error_code = error_code
##
## def get_error_code( self ):
## return self.error_code
##
## def get_packet( self ):
## return self.packet
##
## def __str__( self ):
## key = self.error_code
## if (rpc_status_codes.has_key(key)):
## error_msg_short = rpc_status_codes[key]
## return 'DCERPC Runtime Error: code: 0x%x - %s ' % (self.error_code, error_msg_short)
## else:
## return 'DCERPC Runtime Error: unknown error code: 0x%x' % (self.error_code)
# Context Item
class CtxItem(Structure):
structure = (
('ContextID','<H=0'),
('TransItems','B=0'),
('Pad','B=0'),
('AbstractSyntax','20s=""'),
('TransferSyntax','20s=""'),
)
class CtxItemResult(Structure):
structure = (
('Result','<H=0'),
('Reason','<H=0'),
('TransferSyntax','20s=""'),
)
class SEC_TRAILER(Structure):
commonHdr = (
('auth_type', 'B=10'),
('auth_level','B=0'),
('auth_pad_len','B=0'),
('auth_rsvrd','B=0'),
('auth_ctx_id','<L=747920'),
)
class MSRPCHeader(Structure):
_SIZE = 16
commonHdr = (
('ver_major','B=5'), # 0
('ver_minor','B=0'), # 1
('type','B=0'), # 2
('flags','B=0'), # 3
('representation','<L=0x10'), # 4
('frag_len','<H=self._SIZE+len(auth_data)+(16 if (self["flags"] & 0x80) > 0 else 0)+len(pduData)+len(pad)+len(sec_trailer)'), # 8
('auth_len','<H=len(auth_data)'), # 10
('call_id','<L=1'), # 12 <-- Common up to here (including this)
)
structure = (
('dataLen','_-pduData','self["frag_len"]-self["auth_len"]-self._SIZE-(8 if self["auth_len"] > 0 else 0)'),
('pduData',':'),
('_pad', '_-pad','(4 - ((self._SIZE + (16 if (self["flags"] & 0x80) > 0 else 0) + len(self["pduData"])) & 3) & 3)'),
('pad', ':'),
('_sec_trailer', '_-sec_trailer', '8 if self["auth_len"] > 0 else 0'),
('sec_trailer',':'),
('auth_dataLen','_-auth_data','self["auth_len"]'),
('auth_data',':'),
)
def __init__(self, data = None, alignment = 0):
Structure.__init__(self,data, alignment)
if data is None:
self['ver_major'] = 5
self['ver_minor'] = 0
self['flags'] = MSRPC_FIRSTFRAG | MSRPC_LASTFRAG
self['type'] = MSRPC_REQUEST
self.__frag_len_set = 0
self['auth_len'] = 0
self['pduData'] = ''
self['auth_data'] = ''
self['sec_trailer'] = ''
self['pad'] = ''
def get_header_size(self):
return self._SIZE + (16 if (self["flags"] & MSRPC_NOUUID) > 0 else 0)
def get_packet(self):
if self['auth_data'] != '':
self['auth_len'] = len(self['auth_data'])
# The sec_trailer structure MUST be 4-byte aligned with respect to
# the beginning of the PDU. Padding octets MUST be used to align the
# sec_trailer structure if its natural beginning is not already 4-byte aligned
##self['pad'] = '\xAA' * (4 - ((self._SIZE + len(self['pduData'])) & 3) & 3)
return self.getData()
class MSRPCRequestHeader(MSRPCHeader):
_SIZE = 24
commonHdr = MSRPCHeader.commonHdr + (
('alloc_hint','<L=0'), # 16
('ctx_id','<H=0'), # 20
('op_num','<H=0'), # 22
('_uuid','_-uuid','16 if self["flags"] & 0x80 > 0 else 0' ), # 22
('uuid',':'), # 22
)
def __init__(self, data = None, alignment = 0):
MSRPCHeader.__init__(self, data, alignment)
if data is None:
self['type'] = MSRPC_REQUEST
self['ctx_id'] = 0
self['uuid'] = ''
class MSRPCRespHeader(MSRPCHeader):
_SIZE = 24
commonHdr = MSRPCHeader.commonHdr + (
('alloc_hint','<L=0'), # 16
('ctx_id','<H=0'), # 20
('cancel_count','<B=0'), # 22
('padding','<B=0'), # 23
)
def __init__(self, aBuffer = None, alignment = 0):
MSRPCHeader.__init__(self, aBuffer, alignment)
if aBuffer is None:
self['type'] = MSRPC_RESPONSE
self['ctx_id'] = 0
class MSRPCBind(Structure):
_CTX_ITEM_LEN = len(CtxItem())
structure = (
('max_tfrag','<H=4280'),
('max_rfrag','<H=4280'),
('assoc_group','<L=0'),
('ctx_num','B=0'),
('Reserved','B=0'),
('Reserved2','<H=0'),
('_ctx_items', '_-ctx_items', 'self["ctx_num"]*self._CTX_ITEM_LEN'),
('ctx_items',':'),
)
def __init__(self, data = None, alignment = 0):
Structure.__init__(self, data, alignment)
if data is None:
self['max_tfrag'] = 4280
self['max_rfrag'] = 4280
self['assoc_group'] = 0
self['ctx_num'] = 1
self['ctx_items'] = ''
self.__ctx_items = []
def addCtxItem(self, item):
self.__ctx_items.append(item)
def getData(self):
self['ctx_num'] = len(self.__ctx_items)
for i in self.__ctx_items:
self['ctx_items'] += i.getData()
return Structure.getData(self)
class MSRPCBindAck(MSRPCHeader):
_SIZE = 26 # Up to SecondaryAddr
_CTX_ITEM_LEN = len(CtxItemResult())
structure = (
('max_tfrag','<H=0'),
('max_rfrag','<H=0'),
('assoc_group','<L=0'),
('SecondaryAddrLen','<H&SecondaryAddr'),
('SecondaryAddr','z'), # Optional if SecondaryAddrLen == 0
('PadLen','_-Pad','(4-((self["SecondaryAddrLen"]+self._SIZE) % 4))%4'),
('Pad',':'),
('ctx_num','B=0'),
('Reserved','B=0'),
('Reserved2','<H=0'),
('_ctx_items','_-ctx_items','self["ctx_num"]*self._CTX_ITEM_LEN'),
('ctx_items',':'),
('_sec_trailer', '_-sec_trailer', '8 if self["auth_len"] > 0 else 0'),
('sec_trailer',':'),
('auth_dataLen','_-auth_data','self["auth_len"]'),
('auth_data',':'),
)
def __init__(self, data = None, alignment = 0):
self.__ctx_items = []
MSRPCHeader.__init__(self,data,alignment)
if data is None:
self['Pad'] = ''
self['ctx_items'] = ''
self['sec_trailer'] = ''
self['auth_data'] = ''
def getCtxItems(self):
return self.__ctx_items
def getCtxItem(self,index):
return self.__ctx_items[index-1]
def fromString(self, data):
Structure.fromString(self,data)
# Parse the ctx_items
data = self['ctx_items']
for i in range(self['ctx_num']):
item = CtxItemResult(data)
self.__ctx_items.append(item)
data = data[len(item):]
class MSRPCBindNak(Structure):
structure = (
('RejectedReason','<H=0'),
('SupportedVersions',':'),
)
def __init__(self, data = None, alignment = 0):
Structure.__init__(self,data,alignment)
if data is None:
self['SupportedVersions'] = ''

106
py3-kms/filetimes.py Normal file
View File

@ -0,0 +1,106 @@
#!/usr/bin/env python3
# Copyright (c) 2009, David Buxton <david@gasmark6.com>
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""Tools to convert between Python datetime instances and Microsoft times.
"""
from datetime import datetime, timedelta, tzinfo
from calendar import timegm
# http://support.microsoft.com/kb/167296
# How To Convert a UNIX time_t to a Win32 FILETIME or SYSTEMTIME
EPOCH_AS_FILETIME = 116444736000000000 # January 1, 1970 as MS file time
HUNDREDS_OF_NANOSECONDS = 10000000
ZERO = timedelta(0)
HOUR = timedelta(hours=1)
class UTC(tzinfo):
"""UTC"""
def utcoffset(self, dt):
return ZERO
def tzname(self, dt):
return "UTC"
def dst(self, dt):
return ZERO
utc = UTC()
def dt_to_filetime(dt):
"""Converts a datetime to Microsoft filetime format. If the object is
time zone-naive, it is forced to UTC before conversion.
>>> "%.0f" % dt_to_filetime(datetime(2009, 7, 25, 23, 0))
'128930364000000000'
>>> "%.0f" % dt_to_filetime(datetime(1970, 1, 1, 0, 0, tzinfo=utc))
'116444736000000000'
>>> "%.0f" % dt_to_filetime(datetime(1970, 1, 1, 0, 0))
'116444736000000000'
>>> dt_to_filetime(datetime(2009, 7, 25, 23, 0, 0, 100))
128930364000001000
"""
if (dt.tzinfo is None) or (dt.tzinfo.utcoffset(dt) is None):
dt = dt.replace(tzinfo=utc)
ft = EPOCH_AS_FILETIME + (timegm(dt.timetuple()) * HUNDREDS_OF_NANOSECONDS)
return ft + (dt.microsecond * 10)
def filetime_to_dt(ft):
"""Converts a Microsoft filetime number to a Python datetime. The new
datetime object is time zone-naive but is equivalent to tzinfo=utc.
>>> filetime_to_dt(116444736000000000)
datetime.datetime(1970, 1, 1, 0, 0)
>>> filetime_to_dt(128930364000000000)
datetime.datetime(2009, 7, 25, 23, 0)
>>> filetime_to_dt(128930364000001000)
datetime.datetime(2009, 7, 25, 23, 0, 0, 100)
"""
# Get seconds and remainder in terms of Unix epoch
(s, ns100) = divmod(ft - EPOCH_AS_FILETIME, HUNDREDS_OF_NANOSECONDS)
# Convert to datetime object
dt = datetime.utcfromtimestamp(s)
# Add remainder in as microseconds. Python 3.2 requires an integer
dt = dt.replace(microsecond=(ns100 // 10))
return dt
if __name__ == "__main__":
import doctest
doctest.testmod()

113
py3-kms/formatText.py Normal file
View File

@ -0,0 +1,113 @@
#!/usr/bin/env python3
import sys
def byterize(obj):
objdict = obj.__dict__['fields']
def do_encode(dictio, key):
if isinstance(dictio[key], str) and len(dictio[key]) > 0 and key not in ['SecondaryAddr']:
dictio[key] = dictio[key].encode('latin-1')
elif hasattr(dictio[key], '__dict__'):
subdictio = dictio[key].__dict__['fields']
for subkey in subdictio:
do_encode(subdictio, subkey)
for field in objdict:
do_encode(objdict, field)
return obj
def justify(astring, indent = 35, break_every = 100):
str_indent = ('\n' + ' ' * indent)
splitted = astring.split('\n')
longests = [(n, s) for n, s in enumerate(splitted) if len(s) >= break_every]
for longest in longests:
lines = []
for i in range(0, len(longest[1]), break_every):
lines.append(longest[1][i : i + break_every])
splitted[longest[0]] = str_indent.join(lines)
if len(splitted) > 1:
justy = str_indent.join(splitted)
else:
justy = str_indent + str_indent.join(splitted)
return justy
class ShellStyle(object):
def style(self, s, style):
return style + s + '\033[0m'
def green(self, s):
return self.style(s, '\033[92m')
def blue(self, s):
return self.style(s, '\033[94m')
def yellow(self, s):
return self.style(s, '\033[93m')
def red(self, s):
return self.style(s, '\033[91m')
def magenta(self, s):
return self.style(s, '\033[95m')
def cyan(self, s):
return self.style(s, '\033[96m')
def white(self, s):
return self.style(s, '\033[97m')
def bold(self, s):
return self.style(s, '\033[1m')
def underline(self, s):
return self.style(s, '\033[4m')
def shell_message(nshell):
shelldict = {0: ShellStyle().yellow("Client generating RPC Bind Request..."),
1: ShellStyle().yellow("Client sending RPC Bind Request...") + ShellStyle().red("\t\t\t\t===============>"),
2: ShellStyle().red("===============>\t\t") + ShellStyle().yellow("Server received RPC Bind Request !!!"),
3: ShellStyle().yellow("\t\t\t\tServer parsing RPC Bind Request..."),
4: ShellStyle().yellow("\t\t\t\tServer generating RPC Bind Response..."),
5: ShellStyle().red("<===============\t\t") + ShellStyle().yellow("Server sending RPC Bind Response..."),
6: ShellStyle().green("\t\t\t\tRPC Bind acknowledged !!!\n"),
7: ShellStyle().yellow("Client received RPC Bind Response !!!") + ShellStyle().red("\t\t\t\t<==============="),
8: ShellStyle().green("RPC Bind acknowledged !!!\n"),
9: ShellStyle().blue("Client generating Activation Request dictionary..."),
10: ShellStyle().blue("Client generating Activation Request data..."),
11: ShellStyle().blue("Client generating RPC Activation Request..."),
12: ShellStyle().blue("Client sending RPC Activation Request...") + ShellStyle().red("\t\t\t===============>"),
13: ShellStyle().red("===============>\t\t") + ShellStyle().blue("Server received RPC Activation Request !!!"),
14: ShellStyle().blue("\t\t\t\tServer parsing RPC Activation Request..."),
15: ShellStyle().blue("\t\t\t\tServer processing KMS Activation Request..."),
16: ShellStyle().blue("\t\t\t\tServer processing KMS Activation Response..."),
17: ShellStyle().blue("\t\t\t\tServer generating RPC Activation Response..."),
18: ShellStyle().red("<===============\t\t") + ShellStyle().blue("Server sending RPC Activation Response..."),
19: ShellStyle().green("\t\t\t\tServer responded, now in Stand by...\n"),
20: ShellStyle().blue("Client received Response !!!") + ShellStyle().red("\t\t\t\t\t<==============="),
21: ShellStyle().green("Activation Done !!!"),
-1: ShellStyle().red("\t\t\t\t\t\t\t\tServer receiving"),
-2: ShellStyle().red("Client sending"),
-3: ShellStyle().red("Client receiving"),
-4: ShellStyle().red("\t\t\t\t\t\t\t\tServer sending")
}
if isinstance(nshell, list):
for n in nshell:
print(shelldict[n])
else:
print(shelldict[nshell])

638
py3-kms/kmsBase.py Normal file
View File

@ -0,0 +1,638 @@
#!/usr/bin/env python3
import binascii
import logging
import datetime
import os
import struct
import sys
import time
import uuid
from structure import Structure
import filetimes
import kmsPidGenerator
from formatText import justify, shell_message, byterize
# sqlite3 is optional
try:
import sqlite3
except:
pass
class UUID(Structure):
commonHdr = ()
structure = (
('raw', '16s'),
)
def get(self):
return uuid.UUID(bytes_le=str(self).encode('latin-1')) #*2to3*
class kmsBase:
class kmsRequestStruct(Structure):
commonHdr = ()
structure = (
('versionMinor', '<H'),
('versionMajor', '<H'),
('isClientVm', '<I'),
('licenseStatus', '<I'),
('graceTime', '<I'),
('applicationId', ':', UUID),
('skuId', ':', UUID),
('kmsCountedId' , ':', UUID),
('clientMachineId', ':', UUID),
('requiredClientCount', '<I'),
('requestTime', '<Q'),
('previousClientMachineId', ':', UUID),
('machineName', 'u'),
('_mnPad', '_-mnPad', '126-len(machineName)'),
('mnPad', ':'),
)
def getMachineName(self):
return self['machineName'].decode('utf-16le')
def getLicenseStatus(self):
return kmsBase.licenseStates[self['licenseStatus']] or "Unknown"
class kmsResponseStruct(Structure):
commonHdr = ()
structure = (
('versionMinor', '<H'),
('versionMajor', '<H'),
('epidLen', '<I=len(kmsEpid)+2'),
('kmsEpid', 'u'),
('clientMachineId', ':', UUID),
('responseTime', '<Q'),
('currentClientCount', '<I'),
('vLActivationInterval', '<I'),
('vLRenewalInterval', '<I'),
)
class GenericRequestHeader(Structure):
commonHdr = ()
structure = (
('bodyLength1', '<I'),
('bodyLength2', '<I'),
('versionMinor', '<H'),
('versionMajor', '<H'),
('remainder', '_'),
)
appIds = {
uuid.UUID("55C92734-D682-4D71-983E-D6EC3F16059F") : "Windows",
uuid.UUID("59A52881-A989-479D-AF46-F275C6370663") : "Office 14 (2010)",
uuid.UUID("0FF1CE15-A989-479D-AF46-F275C6370663") : "Office 15 (2013) / Office 16 (2016)"
}
skuIds = {
#########################
## Windows Server 2016 ##
#########################
uuid.UUID("21c56779-b449-4d20-adfc-eece0e1ad74b") : "Windows Server 2016 Datacenter",
uuid.UUID("8c1c5410-9f39-4805-8c9d-63a07706358f") : "Windows Server 2016 Standard",
uuid.UUID("2b5a1b0f-a5ab-4c54-ac2f-a6d94824a283") : "Windows Server 2016 Essentials",
uuid.UUID("7b4433f4-b1e7-4788-895a-c45378d38253") : "Windows Server 2016 Cloud Storage",
uuid.UUID("3dbf341b-5f6c-4fa7-b936-699dce9e263f") : "Windows Server 2016 Azure Core",
################
## Windows 10 ##
################
uuid.UUID("2de67392-b7a7-462a-b1ca-108dd189f588") : "Windows 10 Professional",
uuid.UUID("a80b5abf-76ad-428b-b05d-a47d2dffeebf") : "Windows 10 Professional N",
uuid.UUID("3f1afc82-f8ac-4f6c-8005-1d233e606eee") : "Windows 10 Professional Education",
uuid.UUID("5300b18c-2e33-4dc2-8291-47ffcec746dd") : "Windows 10 Professional Education N",
uuid.UUID("e0c42288-980c-4788-a014-c080d2e1926e") : "Windows 10 Education",
uuid.UUID("3c102355-d027-42c6-ad23-2e7ef8a02585") : "Windows 10 Education N",
uuid.UUID("73111121-5638-40f6-bc11-f1d7b0d64300") : "Windows 10 Enterprise",
uuid.UUID("e272e3e2-732f-4c65-a8f0-484747d0d947") : "Windows 10 Enterprise N",
uuid.UUID("7b51a46c-0c04-4e8f-9af4-8496cca90d5e") : "Windows 10 Enterprise 2015 LTSB",
uuid.UUID("87b838b7-41b6-4590-8318-5797951d8529") : "Windows 10 Enterprise 2015 LTSB N",
uuid.UUID("2d5a5a60-3040-48bf-beb0-fcd770c20ce0") : "Windows 10 Enterprise 2016 LTSB",
uuid.UUID("9f776d83-7156-45b2-8a5c-359b9c9f22a3") : "Windows 10 Enterprise 2016 LTSB N",
uuid.UUID("58e97c99-f377-4ef1-81d5-4ad5522b5fd8") : "Windows 10 Home / Core",
uuid.UUID("7b9e1751-a8da-4f75-9560-5fadfe3d8e38") : "Windows 10 Home / Core N",
uuid.UUID("cd918a57-a41b-4c82-8dce-1a538e221a83") : "Windows 10 Home / Core Single Language",
uuid.UUID("a9107544-f4a0-4053-a96a-1479abdef912") : "Windows 10 Home / Core Country Specific",
############################
## Windows Server 2012 R2 ##
############################
uuid.UUID("b3ca044e-a358-4d68-9883-aaa2941aca99") : "Windows Server 2012 R2 Standard",
uuid.UUID("00091344-1ea4-4f37-b789-01750ba6988c") : "Windows Server 2012 R2 Datacenter",
uuid.UUID("21db6ba4-9a7b-4a14-9e29-64a60c59301d") : "Windows Server 2012 R2 Essentials",
uuid.UUID("b743a2be-68d4-4dd3-af32-92425b7bb623") : "Windows Server 2012 R2 Cloud Storage",
#################
## Windows 8.1 ##
#################
uuid.UUID("c06b6981-d7fd-4a35-b7b4-054742b7af67") : "Windows 8.1 Professional",
uuid.UUID("7476d79f-8e48-49b4-ab63-4d0b813a16e4") : "Windows 8.1 Professional N",
uuid.UUID("096ce63d-4fac-48a9-82a9-61ae9e800e5f") : "Windows 8.1 Professional WMC",
uuid.UUID("81671aaf-79d1-4eb1-b004-8cbbe173afea") : "Windows 8.1 Enterprise",
uuid.UUID("113e705c-fa49-48a4-beea-7dd879b46b14") : "Windows 8.1 Enterprise N",
uuid.UUID("f7e88590-dfc7-4c78-bccb-6f3865b99d1a") : "Windows 8.1 Embedded Industry Automotive",
uuid.UUID("cd4e2d9f-5059-4a50-a92d-05d5bb1267c7") : "Windows 8.1 Embedded Industry Enterprise",
uuid.UUID("0ab82d54-47f4-4acb-818c-cc5bf0ecb649") : "Windows 8.1 Embedded Industry Professional",
uuid.UUID("fe1c3238-432a-43a1-8e25-97e7d1ef10f3") : "Windows 8.1 Core",
uuid.UUID("78558a64-dc19-43fe-a0d0-8075b2a370a3") : "Windows 8.1 Core N",
uuid.UUID("c72c6a1d-f252-4e7e-bdd1-3fca342acb35") : "Windows 8.1 Core Single Language",
uuid.UUID("db78b74f-ef1c-4892-abfe-1e66b8231df6") : "Windows 8.1 Core Country Specific",
uuid.UUID("ffee456a-cd87-4390-8e07-16146c672fd0") : "Windows 8.1 Core ARM",
uuid.UUID("e9942b32-2e55-4197-b0bd-5ff58cba8860") : "Windows 8.1 Core Connected",
uuid.UUID("c6ddecd6-2354-4c19-909b-306a3058484e") : "Windows 8.1 Core Connected N",
uuid.UUID("ba998212-460a-44db-bfb5-71bf09d1c68b") : "Windows 8.1 Core Connected Country Specific",
uuid.UUID("b8f5e3a3-ed33-4608-81e1-37d6c9dcfd9c") : "Windows 8.1 Core Connected Single Language",
uuid.UUID("e58d87b5-8126-4580-80fb-861b22f79296") : "Windows 8.1 Professional Student",
uuid.UUID("cab491c7-a918-4f60-b502-dab75e334f40") : "Windows 8.1 Professional Student N",
#########################
## Windows Server 2012 ##
#########################
uuid.UUID("c04ed6bf-55c8-4b47-9f8e-5a1f31ceee60") : "Windows Server 2012 / Windows 8 Core",
uuid.UUID("197390a0-65f6-4a95-bdc4-55d58a3b0253") : "Windows Server 2012 N / Windows 8 Core N",
uuid.UUID("8860fcd4-a77b-4a20-9045-a150ff11d609") : "Windows Server 2012 Single Language / Windows 8 Core Single Language",
uuid.UUID("9d5584a2-2d85-419a-982c-a00888bb9ddf") : "Windows Server 2012 Country Specific / Windows 8 Core Country Specific",
uuid.UUID("f0f5ec41-0d55-4732-af02-440a44a3cf0f") : "Windows Server 2012 Standard",
uuid.UUID("7d5486c7-e120-4771-b7f1-7b56c6d3170c") : "Windows Server 2012 MultiPoint Standard",
uuid.UUID("95fd1c83-7df5-494a-be8b-1300e1c9d1cd") : "Windows Server 2012 MultiPoint Premium",
uuid.UUID("d3643d60-0c42-412d-a7d6-52e6635327f6") : "Windows Server 2012 Datacenter",
#########################
## Windows Server 2010 ##
#########################
uuid.UUID("f772515c-0e87-48d5-a676-e6962c3e1195") : "Windows MultiPoint Server 2010",
###############
## Windows 8 ##
###############
uuid.UUID("a98bcd6d-5343-4603-8afe-5908e4611112") : "Windows 8 Professional",
uuid.UUID("ebf245c1-29a8-4daf-9cb1-38dfc608a8c8") : "Windows 8 Professional N",
uuid.UUID("a00018a3-f20f-4632-bf7c-8daa5351c914") : "Windows 8 Professional WMC",
uuid.UUID("458e1bec-837a-45f6-b9d5-925ed5d299de") : "Windows 8 Enterprise",
uuid.UUID("e14997e7-800a-4cf7-ad10-de4b45b578db") : "Windows 8 Enterprise N",
uuid.UUID("10018baf-ce21-4060-80bd-47fe74ed4dab") : "Windows 8 Embedded Industry Professional",
uuid.UUID("18db1848-12e0-4167-b9d7-da7fcda507db") : "Windows 8 Embedded Industry Enterprise",
uuid.UUID("af35d7b7-5035-4b63-8972-f0b747b9f4dc") : "Windows 8 Core ARM",
############################
## Windows Server 2008 R2 ##
############################
uuid.UUID("a78b8bd9-8017-4df5-b86a-09f756affa7c") : "Windows Server 2008 R2 Web",
uuid.UUID("cda18cf3-c196-46ad-b289-60c072869994") : "Windows Server 2008 R2 HPC Edition (Compute Cluster)",
uuid.UUID("68531fb9-5511-4989-97be-d11a0f55633f") : "Windows Server 2008 R2 Standard",
uuid.UUID("620e2b3d-09e7-42fd-802a-17a13652fe7a") : "Windows Server 2008 R2 Enterprise",
uuid.UUID("7482e61b-c589-4b7f-8ecc-46d455ac3b87") : "Windows Server 2008 R2 Datacenter",
uuid.UUID("8a26851c-1c7e-48d3-a687-fbca9b9ac16b") : "Windows Server 2008 R2 for Itanium-based Systems",
###############
## Windows 7 ##
###############
uuid.UUID("b92e9980-b9d5-4821-9c94-140f632f6312") : "Windows 7 Professional",
uuid.UUID("54a09a0d-d57b-4c10-8b69-a842d6590ad5") : "Windows 7 Professional N",
uuid.UUID("5a041529-fef8-4d07-b06f-b59b573b32d2") : "Windows 7 Professional E",
uuid.UUID("ae2ee509-1b34-41c0-acb7-6d4650168915") : "Windows 7 Enterprise",
uuid.UUID("1cb6d605-11b3-4e14-bb30-da91c8e3983a") : "Windows 7 Enterprise N",
uuid.UUID("46bbed08-9c7b-48fc-a614-95250573f4ea") : "Windows 7 Enterprise E",
uuid.UUID("db537896-376f-48ae-a492-53d0547773d0") : "Windows 7 Embedded POSReady",
uuid.UUID("aa6dd3aa-c2b4-40e2-a544-a6bbb3f5c395") : "Windows 7 Embedded ThinPC",
uuid.UUID("e1a8296a-db37-44d1-8cce-7bc961d59c54") : "Windows 7 Embedded Standard",
#########################
## Windows Server 2008 ##
#########################
uuid.UUID("ddfa9f7c-f09e-40b9-8c1a-be877a9a7f4b") : "Windows Server 2008 Web",
uuid.UUID("ad2542d4-9154-4c6d-8a44-30f11ee96989") : "Windows Server 2008 Standard",
uuid.UUID("2401e3d0-c50a-4b58-87b2-7e794b7d2607") : "Windows Server 2008 Standard without Hyper-V",
uuid.UUID("c1af4d90-d1bc-44ca-85d4-003ba33db3b9") : "Windows Server 2008 Enterprise",
uuid.UUID("8198490a-add0-47b2-b3ba-316b12d647b4") : "Windows Server 2008 Enterprise without Hyper-V",
uuid.UUID("7afb1156-2c1d-40fc-b260-aab7442b62fe") : "Windows Server 2008 HPC Edition (Compute Cluster)",
uuid.UUID("68b6e220-cf09-466b-92d3-45cd964b9509") : "Windows Server 2008 Datacenter",
uuid.UUID("fd09ef77-5647-4eff-809c-af2b64659a45") : "Windows Server 2008 Datacenter without Hyper-V",
uuid.UUID("01ef176b-3e0d-422a-b4f8-4ea880035e8f") : "Windows Server 2008 for Itanium-based Systems",
###################
## Windows Vista ##
###################
uuid.UUID("4f3d1606-3fea-4c01-be3c-8d671c401e3b") : "Windows Vista Business",
uuid.UUID("2c682dc2-8b68-4f63-a165-ae291d4cf138") : "Windows Vista Business N",
uuid.UUID("cfd8ff08-c0d7-452b-9f60-ef5c70c32094") : "Windows Vista Enterprise",
uuid.UUID("d4f54950-26f2-4fb4-ba21-ffab16afcade") : "Windows Vista Enterprise N",
#################
## Office 2016 ##
#################
uuid.UUID("d450596f-894d-49e0-966a-fd39ed4c4c64") : "Office Professional Plus 2016",
uuid.UUID("dedfa23d-6ed1-45a6-85dc-63cae0546de6") : "Office Standard 2016",
uuid.UUID("4f414197-0fc2-4c01-b68a-86cbb9ac254c") : "Office Project Professional 2016",
uuid.UUID("829b8110-0e6f-4349-bca4-42803577788d") : "Office Project Professional 2016 [Click-to-Run]",
uuid.UUID("da7ddabc-3fbe-4447-9e01-6ab7440b4cd4") : "Office Project Standard 2016",
uuid.UUID("cbbaca45-556a-4416-ad03-bda598eaa7c8") : "Office Project Standard 2016 [Click-to-Run]",
uuid.UUID("6bf301c1-b94a-43e9-ba31-d494598c47fb") : "Office Visio Professional 2016",
uuid.UUID("b234abe3-0857-4f9c-b05a-4dc314f85557") : "Office Visio Professional 2016 [Click-to-Run]",
uuid.UUID("aa2a7821-1827-4c2c-8f1d-4513a34dda97") : "Office Visio Standard 2016",
uuid.UUID("361fe620-64f4-41b5-ba77-84f8e079b1f7") : "Office Visio Standard 2016 [Click-to-Run]",
uuid.UUID("67c0fc0c-deba-401b-bf8b-9c8ad8395804") : "Office Access 2016",
uuid.UUID("c3e65d36-141f-4d2f-a303-a842ee756a29") : "Office Excel 2016",
uuid.UUID("9caabccb-61b1-4b4b-8bec-d10a3c3ac2ce") : "Office Mondo 2016",
uuid.UUID("e914ea6e-a5fa-4439-a394-a9bb3293ca09") : "Office Mondo Retail 2016",
uuid.UUID("d8cace59-33d2-4ac7-9b1b-9b72339c51c8") : "Office OneNote 2016",
uuid.UUID("ec9d9265-9d1e-4ed0-838a-cdc20f2551a1") : "Office Outlook 2016",
uuid.UUID("d70b1bba-b893-4544-96e2-b7a318091c33") : "Office Powerpoint 2016",
uuid.UUID("041a06cb-c5b8-4772-809f-416d03d16654") : "Office Publisher 2016",
uuid.UUID("83e04ee1-fa8d-436d-8994-d31a862cab77") : "Office Skype for Business 2016",
uuid.UUID("bb11badf-d8aa-470e-9311-20eaf80fe5cc") : "Office Word 2016",
#################
## Office 2013 ##
#################
uuid.UUID("87d2b5bf-d47b-41fb-af62-71c382f5cc85") : "Office Professional Plus 2013 [Preview]",
uuid.UUID("b322da9c-a2e2-4058-9e4e-f59a6970bd69") : "Office Professional Plus 2013",
uuid.UUID("b13afb38-cd79-4ae5-9f7f-eed058d750ca") : "Office Standard 2013",
uuid.UUID("3cfe50a9-0e03-4b29-9754-9f193f07b71f") : "Office Project Professional 2013 [Preview]",
uuid.UUID("4a5d124a-e620-44ba-b6ff-658961b33b9a") : "Office Project Professional 2013",
uuid.UUID("39e49e57-ae68-4ee3-b098-26480df3da96") : "Office Project Standard 2013 [Preview]",
uuid.UUID("427a28d1-d17c-4abf-b717-32c780ba6f07") : "Office Project Standard 2013",
uuid.UUID("cfbfd60e-0b5f-427d-917c-a4df42a80e44") : "Office Visio Professional 2013 [Preview]",
uuid.UUID("e13ac10e-75d0-4aff-a0cd-764982cf541c") : "Office Visio Professional 2013",
uuid.UUID("7012cc81-8887-42e9-b17d-4e5e42760f0d") : "Office Visio Standard 2013 [Preview]",
uuid.UUID("ac4efaf0-f81f-4f61-bdf7-ea32b02ab117") : "Office Visio Standard 2013",
uuid.UUID("44b538e2-fb34-4732-81e4-644c17d2e746") : "Office Access 2013 [Preview]",
uuid.UUID("6ee7622c-18d8-4005-9fb7-92db644a279b") : "Office Access 2013",
uuid.UUID("9373bfa0-97b3-4587-ab73-30934461d55c") : "Office Excel 2013 [Preview]",
uuid.UUID("f7461d52-7c2b-43b2-8744-ea958e0bd09a") : "Office Excel 2013",
uuid.UUID("67c0f908-184f-4f64-8250-12db797ab3c3") : "Office OneNote 2013 [Preview]",
uuid.UUID("efe1f3e6-aea2-4144-a208-32aa872b6545") : "Office OneNote 2013",
uuid.UUID("7bce4e7a-dd80-4682-98fa-f993725803d2") : "Office Outlook 2013 [Preview]",
uuid.UUID("771c3afa-50c5-443f-b151-ff2546d863a0") : "Office OutLook 2013",
uuid.UUID("1ec10c0a-54f6-453e-b85a-6fa1bbfea9b7") : "Office PowerPoint 2013 [Preview]",
uuid.UUID("8c762649-97d1-4953-ad27-b7e2c25b972e") : "Office PowerPoint 2013",
uuid.UUID("15aa2117-8f79-49a8-8317-753026d6a054") : "Office Publisher 2013 [Preview]",
uuid.UUID("00c79ff1-6850-443d-bf61-71cde0de305f") : "Office Publisher 2013",
uuid.UUID("7ccc8256-fbaa-49c6-b2a9-f5afb4257cd2") : "Office InfoPath 2013 [Preview]",
uuid.UUID("a30b8040-d68a-423f-b0b5-9ce292ea5a8f") : "Office InfoPath 2013",
uuid.UUID("c53dfe17-cc00-4967-b188-a088a965494d") : "Office Lync 2013 [Preview]",
uuid.UUID("1b9f11e3-c85c-4e1b-bb29-879ad2c909e3") : "Office Lync 2013",
uuid.UUID("de9c7eb6-5a85-420d-9703-fff11bdd4d43") : "Office Word 2013 [Preview]",
uuid.UUID("d9f5b1c6-5386-495a-88f9-9ad6b41ac9b3") : "Office Word 2013",
uuid.UUID("2816a87d-e1ed-4097-b311-e2341c57b179") : "Office Mondo 2013 [Preview]",
uuid.UUID("dc981c6b-fc8e-420f-aa43-f8f33e5c0923") : "Office Mondo 2013",
uuid.UUID("aa286eb4-556f-4eeb-967c-c1b771b7673e") : "Office SharePoint Workspace (Groove) 2013 [Preview]",
uuid.UUID("fb4875ec-0c6b-450f-b82b-ab57d8D1677f") : "Office SharePoint Workspace (Groove) 2013",
## uuid.UUID("???") : "Office SharePoint Designer (Frontpage) 2013 [Preview]",
uuid.UUID("ba3e3833-6a7e-445a-89d0-7802a9a68588") : "Office SharePoint Designer (Frontpage) 2013",
uuid.UUID("1dc00701-03af-4680-b2af-007ffc758a1f") : "Office Mondo Retail 2013",
#################
## Office 2010 ##
#################
uuid.UUID("6f327760-8c5c-417c-9b61-836a98287e0c") : "Office Professional Plus 2010",
uuid.UUID("9da2a678-fb6b-4e67-ab84-60dd6a9c819a") : "Office Standard 2010",
uuid.UUID("df133ff7-bf14-4f95-afe3-7b48e7e331ef") : "Office Project Professional 2010",
uuid.UUID("5dc7bf61-5ec9-4996-9ccb-df806a2d0efe") : "Office Project Standard 2010",
uuid.UUID("e558389c-83c3-4b29-adfe-5e4d7f46c358") : "Office Visio Professional 2010",
uuid.UUID("9ed833ff-4f92-4f36-b370-8683a4f13275") : "Office Visio Standard 2010",
uuid.UUID("92236105-bb67-494f-94c7-7f7a607929bd") : "Office Visio Premium 2010",
uuid.UUID("8ce7e872-188c-4b98-9d90-f8f90b7aad02") : "Office Access 2010",
uuid.UUID("cee5d470-6e3b-4fcc-8c2b-d17428568a9f") : "Office Excel 2010",
uuid.UUID("ab586f5c-5256-4632-962f-fefd8b49e6f4") : "Office OneNote 2010",
uuid.UUID("ecb7c192-73ab-4ded-acf4-2399b095d0cc") : "Office OutLook 2010",
uuid.UUID("45593b1d-dfb1-4e91-bbfb-2d5d0ce2227a") : "Office PowerPoint 2010",
uuid.UUID("b50c4f75-599b-43e8-8dcd-1081a7967241") : "Office Publisher 2010",
uuid.UUID("ca6b6639-4ad6-40ae-a575-14dee07f6430") : "Office InfoPath 2010",
uuid.UUID("8947d0b8-c33b-43e1-8c56-9b674c052832") : "Office SharePoint Workspace (Groove) 2010",
uuid.UUID("2d0882e7-a4e7-423b-8ccc-70d91e0158b1") : "Office Word 2010",
uuid.UUID("ea509e87-07a1-4a45-9edc-eba5a39f36af") : "Office Small Business Basics 2010",
uuid.UUID("2745e581-565a-4670-ae90-6bf7c57ffe43") : "Office Starter 2010 Retail",
## uuid.UUID("???") : "Office SharePoint Designer (Frontpage) 2010",
uuid.UUID("09ed9640-f020-400a-acd8-d7d867dfd9c2") : "Office Mondo 1 2010",
uuid.UUID("ef3d4e49-a53d-4d81-a2b1-2ca6c2556b2c") : "Office Mondo 2 2010",
######################
## Windows Previews ##
######################
uuid.UUID("a4383e6b-dada-423d-a43d-f25678429676") : "Windows 8.1 Professional (Blue) [Preview]",
uuid.UUID("631ead72-a8ab-4df8-bbdf-372029989bdd") : "Windows 8.1 ARM [Beta Pre-Release]",
uuid.UUID("2b9c337f-7a1d-4271-90a3-c6855a2b8a1c") : "Windows 8.1 [Beta Pre-Release]",
uuid.UUID("ba947c44-d19d-4786-b6ae-22770bc94c54") : "Windows Server 2016 Datacenter [Preview]",
uuid.UUID("ff808201-fec6-4fd4-ae16-abbddade5706") : "Windows 10 Professional [Pre-Release]",
uuid.UUID("cf59a07b-1a2a-4be0-bfe0-423b5823e663") : "Windows 8 Professional WMC [RC]",
#################################
## A lot of Previews to define ##
#################################
uuid.UUID("34260150-69ac-49a3-8a0d-4a403ab55763") : "Windows 10 Professional N [Pre-Release]",
uuid.UUID("64192251-81b0-4898-ac63-913cc3edf919") : "Windows XX [XX]",
uuid.UUID("cc17e18a-fa93-43d6-9179-72950a1e931a") : "Windows 10 Professional WMC [Pre-Release]",
uuid.UUID("903663f7-d2ab-49c9-8942-14aa9e0a9c72") : "Windows 10 Home / Core [Pre-Release]",
uuid.UUID("4dfd543d-caa6-4f69-a95f-5ddfe2b89567") : "Windows 10 Home / Core N [Pre-Release]",
uuid.UUID("6496e59d-89dc-49eb-a353-09ceb9404845") : "Windows 10 Home / Core [Pre-Release]",
uuid.UUID("2cc171ef-db48-4adc-af09-7c574b37f139") : "Windows 10 Home / Core Single Language [Pre-Release]",
uuid.UUID("5fe40dd6-cf1f-4cf2-8729-92121ac2e997") : "Windows 10 Home / Core Country Specific [Pre-Release]",
uuid.UUID("af43f7f0-3b1e-4266-a123-1fdb53f4323b") : "Windows 10 Education [Pre-Release]",
uuid.UUID("075aca1f-05d7-42e5-a3ce-e349e7be7078") : "Windows 10 Education N [Pre-Release]",
uuid.UUID("e8ced63e-420d-4ab6-8723-aaf165efb5eb") : "Windows XX Education [Pre-Release]",
uuid.UUID("3885bca5-11c1-4d4e-9395-df38f7f09a0e") : "Windows XX Education N [Pre-Release]",
uuid.UUID("6ae51eeb-c268-4a21-9aae-df74c38b586d") : "Windows 10 Enterprise N [Pre-Release]",
uuid.UUID("c23947f3-3f2e-401f-a38c-f38fe0ecb0bd") : "Windows XX Enterprise N [XX]",
uuid.UUID("38fbe2ac-465a-4ef7-b9d8-72044f2792b6") : "Windows XX Enterprise [XX]",
uuid.UUID("2cf5af84-abab-4ff0-83f8-f040fb2576eb") : "Windows 10 Enterprise XX LTSB [Pre-Release]",
uuid.UUID("11a37f09-fb7f-4002-bd84-f3ae71d11e90") : "Windows 10 Enterprise XX LTSB N [Pre-Release]",
uuid.UUID("75d003b0-dc66-42c0-b3a1-308a3f35741a") : "Windows 10 Enterprise XX LTSB [Pre-Release]",
uuid.UUID("4e4d5504-e7b1-419c-913d-3c80c15294fc") : "Windows 10 Enterprise XX LTSB N [Pre-Release]",
uuid.UUID("43f2ab05-7c87-4d56-b27c-44d0f9a3dabd") : "Windows 10 Enterprise [Pre-Release]",
uuid.UUID("b554b49f-4d57-4f08-955e-87886f514d49") : "Windows 10 Core ARM [Pre-Release]",
uuid.UUID("f18bbe32-16dc-48d4-a27b-5f3966f82513") : "Windows 10 Core Connected N [Pre-Release]",
uuid.UUID("964a60f6-1505-4ddb-af03-6a9ce6997d3b") : "Windows 10 Core Connected Single Language [Pre-Release]",
uuid.UUID("b5fe5eaa-14cc-4075-84ae-57c0206d1133") : "Windows 10 Core Connected Country Specific [Pre-Release]",
uuid.UUID("827a0032-dced-4609-ab6e-16b9d8a40280") : "Windows 10 Core Connected [Pre-Release]",
uuid.UUID("b15187db-11c6-4f13-91ca-8121cebf5b88") : "Windows 10 Professional S [Pre-Release]",
uuid.UUID("6cdbc9fb-63f5-431b-a5c0-c6f19ae26a9b") : "Windows 10 Professional S N [Pre-Release]",
uuid.UUID("aa234c15-ee34-4e5f-adb5-73afafb77143") : "Windows XX Professional S [Pre-Release]",
uuid.UUID("9f6a1bc9-5278-4991-88c9-7301c87a75ea") : "Windows XX Professional S N [Pre-Release]",
uuid.UUID("49066601-00dc-4d2c-83a8-4343a7b990d1") : "Windows 10 Professional Student [Pre-Release]",
uuid.UUID("bd64ebf7-d5ec-44c5-ba00-6813441c8c87") : "Windows 10 Professional Student N [Pre-Release]",
uuid.UUID("5b2add49-b8f4-42e0-a77c-adad4efeeeb1") : "Windows 10 PPIPro [Pre-Release]",
uuid.UUID("3a9a9414-24bf-4836-866d-ba13a298efb0") : "Windows 8 Core ARM [RC]",
uuid.UUID("c8cca3ca-bea8-4f6f-87e0-4d050ce8f0a9") : "Windows 8 Embedded Industry Enterprise [TAP-CTP]",
uuid.UUID("5ca3e488-dbae-4fae-8282-a98fbcd21126") : "Windows 8 Embedded Industry Enterprise [Beta]",
uuid.UUID("cde952c7-2f96-4d9d-8f2b-2d349f64fc51") : "Windows 8.1 Enterprise [Pre-Release]",
uuid.UUID("c436def1-0dcc-4849-9a59-8b6142eb70f3") : "Windows 8.1 Core Connected [Pre-Release]",
uuid.UUID("86f72c8d-8363-4188-b574-1a53cb374711") : "Windows 8.1 Core Connected N [Pre-Release]",
uuid.UUID("a8651bfb-7fe0-40df-b156-87337ecd5acc") : "Windows 8.1 Core Connected Country Specific [Pre-Release]",
uuid.UUID("5b120df4-ea3f-4e82-b0c0-6568f719730e") : "Windows 8.1 Core Connected Single Language [Pre-Release]",
uuid.UUID("fd5ae385-f5cf-4b53-b1fa-1af6fff7c0d8") : "Windows 8.1 Professional Student [Pre-Release]",
uuid.UUID("687f6358-6a21-453a-a712-3b3b57123827") : "Windows 8.1 Professional Student N [Pre-Release]",
uuid.UUID("c35a9336-fb02-48db-8f4d-245c17f03667") : "Windows 8.1 Embedded Industry [Beta]",
uuid.UUID("4daf1e3e-6be9-4848-8f5a-a18a0d2895e1") : "Windows 8.1 Embedded Industry Enterprise [Beta]",
uuid.UUID("9cc2564c-292e-4d8a-b9f9-1f5007d9409a") : "Windows 8.1 Embedded Industry Automotive [Beta]",
uuid.UUID("3ddb92aa-332e-46f9-abb7-8bdf62f8d967") : "Windows Longhorn Web Edition [XX]",
uuid.UUID("7ea4f647-9e67-453b-a7ba-56f7102afde2") : "Windows Longhorn Standard Server [XX]",
uuid.UUID("5a99526c-1c09-4481-80fb-b60e8b3d99f8") : "Windows Longhorn Enterprise Server [XX]",
uuid.UUID("8372b47d-5221-41d8-88d0-3f924e50623e") : "Windows Longhorn Computer Cluster [XX]",
uuid.UUID("932ef1f5-4327-4548-b147-51b0f5502995") : "Windows Longhorn Datacenter Server [XX]",
uuid.UUID("bebf03b1-a184-4c5e-9103-88af08055e68") : "Windows Longhorn Enterprise Server IA64 [XX]",
uuid.UUID("bfa6b683-56be-47b8-a22e-461b27b9cf11") : "Windows Server XX MultiPoint Standard [XX]",
uuid.UUID("bc20fb5b-4097-484f-84d2-55b18dac95eb") : "Windows Server XX MultiPoint Premium [XX]",
uuid.UUID("8a409d61-30fe-4903-bdbc-1fb28603ba3a") : "Windows Server XX Enterprise [XX]",
uuid.UUID("9dce1f29-bb10-4be0-8027-35b953dd46d5") : "Windows 7 Server Enterprise [XX]",
uuid.UUID("bf9eda2f-74cc-4ba3-8967-cde30f18c230") : "Windows 7 Server Enterprise IA64 [XX]",
uuid.UUID("dc06c019-b222-4706-a820-645e77d26a91") : "Windows 7 Server Enterprise without Hyper-V [XX]",
uuid.UUID("d3872724-5c08-4b1b-91f2-fc9eafed4990") : "Windows XX Server Standard [XX]",
uuid.UUID("92374131-ed4c-4d1b-846a-32f43c3eb90d") : "Windows 7 Server Standard [XX]",
uuid.UUID("f963bf4b-9693-46e6-9d9d-09c73eaa2b60") : "Windows 7 Server Standard without Hyper-V [XX]",
uuid.UUID("e5676f13-9b66-4a1f-8b0c-43490e236202") : "Windows XX Server Web [XX]",
uuid.UUID("4f4cfa6c-76d8-49f5-9c41-0a57f8af1bbc") : "Windows 7 Server Web [XX]",
uuid.UUID("0839e017-cfef-4ac6-a97e-ed2ea7962787") : "Windows 7 Server Datacenter without Hyper-V [XX]",
uuid.UUID("cc64c548-1867-4777-a1cc-0022691bc2a0") : "Windows 7 Server Datacenter [XX]",
uuid.UUID("2412bea9-b6e0-441e-8dc2-a13720b42de9") : "Windows XX Server HPC Edition [XX]",
uuid.UUID("c6e3410d-e48d-41eb-8ca9-848397f46d02") : "Windows Server 2012 N / Windows 8 Core N [RC]",
uuid.UUID("b148c3f4-6248-4d2f-8c6d-31cce7ae95c3") : "Windows Server 2012 Single Language / Windows 8 Core Single Language [RC]",
uuid.UUID("c7a8a09a-571c-4ea8-babc-0cbe4d48a89d") : "Windows Server 2012 Country Specific / Windows 8 Core Country Specific [RC]",
uuid.UUID("8f365ba6-c1b9-4223-98fc-282a0756a3ed") : "Windows Server 2012 R2 Essentials [RTM]",
uuid.UUID("b995b62c-eae2-40aa-afb9-111889a84ef4") : "Windows XX Server HI [Beta]",
uuid.UUID("99ff9b26-016a-49d3-982e-fc492f352e57") : "Windows Vista Business [XX]",
uuid.UUID("90284483-de09-44a2-a406-98957f8dd09d") : "Windows Vista Business [XX]",
uuid.UUID("af46f56f-f06b-49f0-a420-caa8a8d2bf8c") : "Windows Vista Business N [XX]",
uuid.UUID("cf67834d-db4a-402c-ab1f-2c134f02b700") : "Windows Vista Enterprise [XX]",
uuid.UUID("14478aca-ea15-4958-ac34-359281101c99") : "Windows Vista Enterprise [XX]",
uuid.UUID("0707c7fc-143d-46a4-a830-3705e908202c") : "Windows Vista Enterprise N [XX]",
uuid.UUID("957ec1e8-97cd-42a8-a091-01a30cf779da") : "Windows 7 Business [XX]",
uuid.UUID("0ff4e536-a746-4018-b107-e81dd0b6d33a") : "Windows 7 Business N [XX]",
uuid.UUID("ea77973e-4930-4fa1-a899-02dfaeada1db") : "Windows 7 Enterprise [XX]",
uuid.UUID("e4ecef68-4372-4740-98e8-6c157cd301c2") : "Windows 7 Enterprise N [XX]",
uuid.UUID("2a4403df-877f-4046-8271-db6fb6ec54c8") : "Enterprise ProdKey3 Win 9984 DLA/Bypass NQR Test",
uuid.UUID("38fbe2ac-465a-4ef7-b9d8-72044f2792b6") : "Windows XX Enterprise [XX]",
}
licenseStates = {
0 : "Unlicensed",
1 : "Activated",
2 : "Grace Period",
3 : "Out-of-Tolerance Grace Period",
4 : "Non-Genuine Grace Period",
5 : "Notifications Mode",
6 : "Extended Grace Period",
}
licenseStatesEnum = {
'unlicensed' : 0,
'licensed' : 1,
'oobGrace' : 2,
'ootGrace' : 3,
'nonGenuineGrace' : 4,
'notification' : 5,
'extendedGrace' : 6
}
errorCodes = {
'SL_E_VL_NOT_WINDOWS_SLP' : 0xC004F035,
'SL_E_VL_NOT_ENOUGH_COUNT' : 0xC004F038,
'SL_E_VL_BINDING_SERVICE_NOT_ENABLED' : 0xC004F039,
'SL_E_VL_INFO_PRODUCT_USER_RIGHT' : 0x4004F040,
'SL_I_VL_OOB_NO_BINDING_SERVER_REGISTRATION' : 0x4004F041,
'SL_E_VL_KEY_MANAGEMENT_SERVICE_ID_MISMATCH' : 0xC004F042,
'SL_E_VL_MACHINE_NOT_BOUND' : 0xC004F056
}
def __init__(self, data, config):
self.data = data
self.config = config
def getConfig(self):
return self.config
def getOptions(self):
return self.config
def getData(self):
return self.data
def getResponse(self):
return ''
def getResponsePadding(self, bodyLength):
if bodyLength % 8 == 0:
paddingLength = 0
else:
paddingLength = 8 - bodyLength % 8
padding = bytearray(paddingLength)
return padding
def serverLogic(self, kmsRequest):
if self.config['sqlite'] and self.config['dbSupport']:
self.dbName = 'clients.db'
if not os.path.isfile(self.dbName):
# Initialize the database.
con = None
try:
con = sqlite3.connect(self.dbName)
cur = con.cursor()
cur.execute("CREATE TABLE clients(clientMachineId TEXT, machineName TEXT, \
applicationId TEXT, skuId TEXT, licenseStatus TEXT, lastRequestTime INTEGER, kmsEpid TEXT, requestCount INTEGER)")
except sqlite3.Error as e: #*2to3*
logging.error("%s:" % e.args[0])
sys.exit(1)
finally:
if con:
con.commit()
con.close()
shell_message(nshell = 15)
kmsRequest = byterize(kmsRequest)
logging.debug("KMS Request Bytes: \n%s\n" % justify(binascii.b2a_hex(str(kmsRequest).encode('latin-1')).decode('utf-8'))) #*2to3*
logging.debug("KMS Request: \n%s\n" % justify(kmsRequest.dump(print_to_stdout = False)))
clientMachineId = kmsRequest['clientMachineId'].get()
applicationId = kmsRequest['applicationId'].get()
skuId = kmsRequest['skuId'].get()
requestDatetime = filetimes.filetime_to_dt(kmsRequest['requestTime'])
# Try and localize the request time, if pytz is available
try:
import timezones
from pytz import utc
local_dt = utc.localize(requestDatetime).astimezone(timezones.localtz())
except ImportError:
local_dt = requestDatetime
infoDict = {
"machineName" : kmsRequest.getMachineName(),
"clientMachineId" : str(clientMachineId),
"appId" : self.appIds.get(applicationId, str(applicationId)),
"skuId" : self.skuIds.get(skuId, str(skuId)),
"licenseStatus" : kmsRequest.getLicenseStatus(),
"requestTime" : int(time.time()),
"kmsEpid" : None
}
#print infoDict
logging.info("Machine Name: %s" % infoDict["machineName"])
logging.info("Client Machine ID: %s" % infoDict["clientMachineId"])
logging.info("Application ID: %s" % infoDict["appId"])
logging.info("SKU ID: %s" % infoDict["skuId"])
logging.info("License Status: %s" % infoDict["licenseStatus"])
logging.info("Request Time: %s" % local_dt.strftime('%Y-%m-%d %H:%M:%S %Z (UTC%z)'))
if self.config['sqlite'] and self.config['dbSupport']:
con = None
try:
con = sqlite3.connect(self.dbName)
cur = con.cursor()
cur.execute("SELECT * FROM clients WHERE clientMachineId=:clientMachineId;", infoDict)
try:
data = cur.fetchone()
if not data:
#print "Inserting row..."
cur.execute("INSERT INTO clients (clientMachineId, machineName, \
applicationId, skuId, licenseStatus, lastRequestTime, requestCount) VALUES (:clientMachineId, :machineName, :appId, \
:skuId, :licenseStatus, :requestTime, 1);", infoDict)
else:
#print "Data:", data
if data[1] != infoDict["machineName"]:
cur.execute("UPDATE clients SET machineName=:machineName WHERE \
clientMachineId=:clientMachineId;", infoDict)
if data[2] != infoDict["appId"]:
cur.execute("UPDATE clients SET applicationId=:appId WHERE \
clientMachineId=:clientMachineId;", infoDict)
if data[3] != infoDict["skuId"]:
cur.execute("UPDATE clients SET skuId=:skuId WHERE \
clientMachineId=:clientMachineId;", infoDict)
if data[4] != infoDict["licenseStatus"]:
cur.execute("UPDATE clients SET licenseStatus=:licenseStatus WHERE \
clientMachineId=:clientMachineId;", infoDict)
if data[5] != infoDict["requestTime"]:
cur.execute("UPDATE clients SET lastRequestTime=:requestTime WHERE \
clientMachineId=:clientMachineId;", infoDict)
# Increment requestCount
cur.execute("UPDATE clients SET requestCount=requestCount+1 WHERE \
clientMachineId=:clientMachineId;", infoDict)
except sqlite3.Error as e: #*2to3*
logging.error("%s:" % e.args[0])
except sqlite3.Error as e: #*2to3*
logging.error("%s:" % e.args[0])
sys.exit(1)
finally:
if con:
con.commit()
con.close()
return self.createKmsResponse(kmsRequest)
def createKmsResponse(self, kmsRequest):
response = self.kmsResponseStruct()
response['versionMinor'] = kmsRequest['versionMinor']
response['versionMajor'] = kmsRequest['versionMajor']
if not self.config["epid"]:
response["kmsEpid"] = kmsPidGenerator.epidGenerator(kmsRequest['applicationId'].get(),
kmsRequest['versionMajor'], self.config["lcid"]).encode('utf-16le')
else:
response["kmsEpid"] = self.config["epid"].encode('utf-16le')
response['clientMachineId'] = kmsRequest['clientMachineId']
response['responseTime'] = kmsRequest['requestTime']
response['currentClientCount'] = self.config["CurrentClientCount"]
response['vLActivationInterval'] = self.config["VLActivationInterval"]
response['vLRenewalInterval'] = self.config["VLRenewalInterval"]
if self.config['sqlite'] and self.config['dbSupport']:
con = None
try:
con = sqlite3.connect(self.dbName)
cur = con.cursor()
cur.execute("SELECT * FROM clients WHERE clientMachineId=?;", [str(kmsRequest['clientMachineId'].get())])
try:
data = cur.fetchone()
if data[6]:
response["kmsEpid"] = data[6].encode('utf-16le')
else:
cur.execute("UPDATE clients SET kmsEpid=? WHERE clientMachineId=?;",
(str(response["kmsEpid"].decode('utf-16le')), str(kmsRequest['clientMachineId'].get())))
except sqlite3.Error as e: #*2to3*
logging.error("%s:" % e.args[0])
except sqlite3.Error as e: #*2to3*
logging.error("%s:" % e.args[0])
sys.exit(1)
finally:
if con:
con.commit()
con.close()
logging.info("Server ePID: %s" % response["kmsEpid"].decode('utf-16le'))
return response
import kmsRequestV4, kmsRequestV5, kmsRequestV6, kmsRequestUnknown
def generateKmsResponseData(data, config):
version = kmsBase.GenericRequestHeader(data)['versionMajor']
currentDate = datetime.datetime.now().ctime()
if version == 4:
logging.info("Received V%d request on %s." % (version, currentDate))
messagehandler = kmsRequestV4.kmsRequestV4(data, config)
messagehandler.executeRequestLogic()
elif version == 5:
logging.info("Received V%d request on %s." % (version, currentDate))
messagehandler = kmsRequestV5.kmsRequestV5(data, config)
messagehandler.executeRequestLogic()
elif version == 6:
logging.info("Received V%d request on %s." % (version, currentDate))
messagehandler = kmsRequestV6.kmsRequestV6(data, config)
messagehandler.executeRequestLogic()
else:
logging.info("Unhandled KMS version V%d." % version)
messagehandler = kmsRequestUnknown.kmsRequestUnknown(data, config)
return messagehandler.getResponse()

136
py3-kms/kmsPidGenerator.py Normal file
View File

@ -0,0 +1,136 @@
#!/usr/bin/env python3
import datetime
import random
import time
import uuid
APP_ID_WINDOWS = uuid.UUID("55C92734-D682-4D71-983E-D6EC3F16059F")
APP_ID_OFFICE14 = uuid.UUID("59A52881-A989-479D-AF46-F275C6370663")
APP_ID_OFFICE15 = uuid.UUID("0FF1CE15-A989-479D-AF46-F275C6370663") # also valid for Office 16 (2016).
# KMS Host OS Type
hostOsList = {}
# Windows Server 2008 R2 SP1
hostOsList["HOST_SERVER2008R2"] = {
"type" : 55041,
"osBuild" : 7601
}
# Windows Server 2012 RTM
hostOsList["HOST_SERVER2012"] = {
"type" : 5426,
"osBuild" : 9200
}
# Windows Server 2012 R2 RTM
hostOsList["HOST_SERVER2012R2"] = {
"type" : 6401,
"osBuild" : 9600
}
# Windows Server 2016 RTM
hostOsList["HOST_SERVER2016"] = {
"type" : 3612,
"osBuild" : 14393
}
# Product Specific KeyConfig
pkeyConfigList = {}
# Windows Server KMS Host PID, actual PIDRangeMax = 191999999
pkeyConfigList["windows"] = {
"GroupID" : 206,
"PIDRangeMin" : 152000000,
"PIDRangeMax" : 191999999
}
# Windows Server 2012 R2 KMS Host PID, actual PIDRangeMax = 310999999
pkeyConfigList["windows2012r2"] = {
"GroupID" : 206,
"PIDRangeMin" : 271000000,
"PIDRangeMax" : 310999999
}
# Office 2010 KMSHost Class PID, actual PIDRangeMax = 217999999
pkeyConfigList["office14"] = {
"GroupID" : 96,
"PIDRangeMin" : 199000000,
"PIDRangeMax" : 217999999
}
# Office 2013 KMSHost Class PID, actual PIDRangeMax = 255999999
pkeyConfigList["office15"] = {
"GroupID" : 206,
"PIDRangeMin" : 234000000,
"PIDRangeMax" : 255999999
}
def epidGenerator(appId, version, lcid):
# Generate Part 1 & 7: Host Type and KMS Server OS Build
hostOsType = random.choice(list(hostOsList.keys())) #*2to3*
hostOsDict = hostOsList[hostOsType]
# Generate Part 2: Group ID and Product Key ID Range
if appId == APP_ID_OFFICE14:
keyConfig = pkeyConfigList["office14"]
elif appId == APP_ID_OFFICE15:
keyConfig = pkeyConfigList["office15"]
else:
# Default to Windows
if hostOsDict['osBuild'] == 14393:
keyConfig = pkeyConfigList["windows2012r2"]
elif hostOsDict['osBuild'] == 9600:
keyConfig = pkeyConfigList["windows2012r2"]
else:
keyConfig = pkeyConfigList["windows"]
# Generate Part 3 and Part 4: Product Key ID
productKeyID = random.randint(keyConfig["PIDRangeMin"], keyConfig["PIDRangeMax"])
# Generate Part 5: License Channel (00=Retail, 01=Retail, 02=OEM,
# 03=Volume(GVLK,MAK)) - always 03
licenseChannel = 3
# Generate Part 6: Language - use system default language
# 1033 is en-us
languageCode = lcid # C# CultureInfo.InstalledUICulture.LCID
# Generate Part 8: KMS Host Activation Date
# Get Minimum Possible Date: Newer Products first
if hostOsType == "HOST_SERVER2016":
# Microsoft Windows Server 2016 RTM
minTime = datetime.date(2016, 7, 27)
elif hostOsType == "HOST_SERVER2012R2" or version == 6:
# Microsoft Windows Server 2012 R2 RTM (October 17, 2013)
minTime = datetime.date(2013, 10, 17)
elif appId == APP_ID_OFFICE15:
# Microsoft Office 2013 RTM (October 24, 2012)
minTime = datetime.date(2012, 10, 24)
elif hostOsType == "HOST_SERVER2012" or version == 5:
# Microsoft Windows Server 2012 RTM (September 4, 2012)
minTime = datetime.date(2012, 9, 4)
else:
# Windows Server 2008 R2 SP1 (February 16, 2011)
minTime = datetime.date(2011, 2, 16)
# Generate Year and Day Number
randomDate = datetime.date.fromtimestamp(random.randint(time.mktime(minTime.timetuple()), time.mktime(datetime.datetime.now().timetuple())))
firstOfYear = datetime.date(randomDate.year, 1, 1)
randomDayNumber = int((time.mktime(randomDate.timetuple()) - time.mktime(firstOfYear.timetuple())) / 86400 + 0.5)
# generate the epid string
result = []
result.append(str(hostOsDict["type"]).rjust(5, "0"))
result.append("-")
result.append(str(keyConfig["GroupID"]).rjust(5, "0"))
result.append("-")
result.append(str(productKeyID // 10**6).rjust(3, "0")) #*2to3*
result.append("-")
result.append(str(productKeyID % 10**6).rjust(6, "0"))
result.append("-")
result.append(str(licenseChannel).rjust(2, "0"))
result.append("-")
result.append(str(languageCode))
result.append("-")
result.append(str(hostOsDict["osBuild"]).rjust(4, "0"))
result.append(".0000-")
result.append(str(randomDayNumber).rjust(3, "0"))
result.append(str(randomDate.year).rjust(4, "0"))
return "".join(result)

View File

@ -0,0 +1,13 @@
#!/usr/bin/env python3
import struct
from kmsBase import kmsBase
class kmsRequestUnknown(kmsBase):
def getResponse(self):
finalResponse = bytearray()
finalResponse.extend(bytearray(struct.pack('<I', 0)))
finalResponse.extend(bytearray(struct.pack('<I', 0)))
finalResponse.extend(bytearray(struct.pack('<I', self.errorCodes['SL_E_VL_KEY_MANAGEMENT_SERVICE_ID_MISMATCH'])))
return finalResponse.decode('utf-8').encode('utf-8') #*2to3*

131
py3-kms/kmsRequestV4.py Normal file
View File

@ -0,0 +1,131 @@
#!/usr/bin/env python3
import binascii
import struct
import time
import logging
from kmsBase import kmsBase
from structure import Structure
from aes import AES
from formatText import shell_message, justify, byterize
# 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'])
thehash = self.generateHash(bytearray(str(response).encode('latin-1'))) #*2to3*
self.responseData = self.generateResponse(response, thehash)
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 hashBuffer #*2to3*
def generateResponse(self, responseBuffer, thehash):
bodyLength = len(responseBuffer) + len(thehash)
response = self.ResponseV4()
response['response'] = responseBuffer
response['hash'] = thehash.decode('latin-1') #*2to3*
response['padding'] = self.getResponsePadding(bodyLength).decode('latin-1') #*2to3*
## Debug stuff.
shell_message(nshell = 16)
response = byterize(response)
logging.debug("KMS V4 Response: \n%s\n" % justify(response.dump(print_to_stdout = False)))
logging.debug("KMS V4 Response Bytes: \n%s\n" % 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):
thehash = self.generateHash(bytearray(str(requestBase).encode('latin-1'))) #*2to3*
bodyLength = len(requestBase) + len(thehash)
request = kmsRequestV4.RequestV4()
request['bodyLength1'] = bodyLength
request['bodyLength2'] = bodyLength
request['request'] = requestBase
request['hash'] = thehash.decode('latin-1') #*2to3*
request['padding'] = self.getResponsePadding(bodyLength).decode('latin-1') #*2to3*
## Debug stuff.
shell_message(nshell = 10)
request = byterize(request)
logging.debug("Request V4 Data: \n%s\n" % justify(request.dump(print_to_stdout = False)))
logging.debug("Request V4: \n%s\n" % justify(binascii.b2a_hex(str(request).encode('latin-1')).decode('utf-8'))) #*2to3*
return request

179
py3-kms/kmsRequestV5.py Normal file
View File

@ -0,0 +1,179 @@
#!/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

110
py3-kms/kmsRequestV6.py Normal file
View File

@ -0,0 +1,110 @@
#!/usr/bin/env python3
import binascii
import hashlib
import hmac
import random
import struct
import aes
from kmsBase import kmsBase
from kmsRequestV5 import kmsRequestV5
from structure import Structure
class kmsRequestV6(kmsRequestV5):
class DecryptedResponse(Structure):
class Message(Structure):
commonHdr = ()
structure = (
('response', ':', kmsBase.kmsResponseStruct),
('keys', '16s'),
('hash', '32s'),
('hwid', '8s'),
('xorSalts', '16s'),
)
commonHdr = ()
structure = (
('message', ':', Message),
('hmac', '16s'),
)
key = bytearray([ 0xA9, 0x4A, 0x41, 0x95, 0xE2, 0x01, 0x43, 0x2D, 0x9B, 0xCB, 0x46, 0x04, 0x05, 0xD8, 0x4A, 0x21 ])
v6 = True
ver = 6
def encryptResponse(self, request, decrypted, response):
randomSalt = self.getRandomSalt()
sha256 = hashlib.sha256()
sha256.update(randomSalt) #*2to3*
result = sha256.digest()
SaltC = bytearray(request['message']['salt'].encode('latin-1')) #*2to3*
DSaltC = bytearray(decrypted['salt'].encode('latin-1')) #*2to3*
randomStuff = bytearray(16)
for i in range(0,16):
randomStuff[i] = (SaltC[i] ^ DSaltC[i] ^ randomSalt[i]) & 0xff
# XorSalts
XorSalts = bytearray(16)
for i in range (0, 16):
XorSalts[i] = (SaltC[i] ^ DSaltC[i]) & 0xff
message = self.DecryptedResponse.Message()
message['response'] = response
message['keys'] = randomStuff #*2to3*
message['hash'] = result
message['xorSalts'] = XorSalts #*2to3*
message['hwid'] = self.config['hwid']
# SaltS
SaltS = self.getRandomSalt()
moo = aes.AESModeOfOperation()
moo.aes.v6 = True
decry = moo.decrypt(SaltS, 16, moo.ModeOfOperation["CBC"], self.key, moo.aes.KeySize["SIZE_128"], SaltS) #*2to3*
# DSaltS
DSaltS = bytearray(decry)
# HMacMsg
HMacMsg = bytearray(16)
for i in range(0,16):
HMacMsg[i] = (SaltS[i] ^ DSaltS[i]) & 0xff
HMacMsg.extend(str(message).encode('latin-1')) #*2to3*
# HMacKey
requestTime = decrypted['request']['requestTime']
HMacKey = self.getMACKey(requestTime)
HMac = hmac.new(HMacKey, HMacMsg, hashlib.sha256) #*2to3*
digest = HMac.digest()
responsedata = self.DecryptedResponse()
responsedata['message'] = message
responsedata['hmac'] = digest[16:]
padded = aes.append_PKCS7_padding(str(responsedata).encode('latin-1')) #*2to3*
mode, orig_len, crypted = moo.encrypt(padded, moo.ModeOfOperation["CBC"], self.key, moo.aes.KeySize["SIZE_128"], SaltS) #*2to3*
return SaltS.decode('latin-1').encode('latin-1'), crypted #*2to3*
def getMACKey(self, t):
c1 = 0x00000022816889BD
c2 = 0x000000208CBAB5ED
c3 = 0x3156CD5AC628477A
i1 = (t // c1) & 0xFFFFFFFFFFFFFFFF #*2to3*
i2 = (i1 * c2) & 0xFFFFFFFFFFFFFFFF
seed = (i2 + c3) & 0xFFFFFFFFFFFFFFFF
sha256 = hashlib.sha256()
sha256.update(struct.pack("<Q", seed))
digest = sha256.digest()
return digest[16:]

6
py3-kms/randomHWID.py Normal file
View File

@ -0,0 +1,6 @@
#!/usr/bin/env python3
import uuid
key = uuid.uuid4().hex
print(key[:16]) #*2to3*

38
py3-kms/randomPID.py Normal file
View File

@ -0,0 +1,38 @@
#!/usr/bin/env python3
import uuid
import kmsPidGenerator
# Variables.
# 1033 (english) is en-us
# 1034 (spanish) is es-es
# 1041 (japanese) is ja
lcid = 1033
applicationId = uuid.UUID("55C92734-D682-4D71-983E-D6EC3F16059F") # Windows
applicationId2 = uuid.UUID("0FF1CE15-A989-479D-AF46-F275C6370663") # Office 15 (2013) / Office 16 (2016)
applicationId3 = uuid.UUID("59A52881-A989-479D-AF46-F275C6370663") # Office 14 (2010)
# KMS Version.
# 6 for date starting October 17, 2013
# 5 for date starting September 4, 2012
# 4 for date starting February 16, 2011
versionMajor = 6
# Responses.
response = kmsPidGenerator.epidGenerator(applicationId, versionMajor, lcid)
response2 = kmsPidGenerator.epidGenerator(applicationId2, versionMajor, lcid)
response3 = kmsPidGenerator.epidGenerator(applicationId3, versionMajor, lcid)
print("\nFor Windows: ", response)
print("\nFor Office 2013/2016: ", response2)
print("\nFor Office 2010: ", response3)
#-----------------------------------------------------------------------------
# HWID Section.
import uuid
key = uuid.uuid4().hex
print("\nRandom hwid: ", key[:16])
print("\n")

62
py3-kms/rpcBase.py Normal file
View File

@ -0,0 +1,62 @@
#!/usr/bin/env python3
import struct
import uuid
class rpcBase:
packetType = {
'request': 0,
'ping': 1,
'response': 2,
'fault': 3,
'working': 4,
'nocall': 5,
'reject': 6,
'ack': 7,
'clCancel': 8,
'fack': 9,
'cancelAck': 10,
'bindReq': 11,
'bindAck': 12,
'bindNak': 13,
'alterContext': 14,
'alterContextResp': 15,
'shutdown': 17,
'coCancel': 18,
'orphaned': 19
}
packetFlags = {
'firstFrag': 1, # 0x01
'lastFrag': 2, # 0x02
'cancelPending': 4, # 0x04
'reserved': 8, # 0x08
'multiplex': 16, # 0x10
'didNotExecute': 32, # 0x20
'maybe': 64, # 0x40
'objectUuid': 128 # 0x80
}
def __init__(self, data, config):
self.data = data
self.config = config
def populate(self):
self.requestData = self.parseRequest()
self.responseData = self.generateResponse()
return self
def getConfig(self):
return self.config
def getOptions(self):
return self.config
def getData(self):
return self.data
def parseRequest(self):
return {}
def getResponse(self):
return self.responseData

175
py3-kms/rpcBind.py Normal file
View File

@ -0,0 +1,175 @@
#!/usr/bin/env python3
import logging
import binascii
import struct
import uuid
import rpcBase
from dcerpc import MSRPCHeader, MSRPCBindAck
from structure import Structure
from formatText import shell_message, justify, byterize
uuidNDR32 = uuid.UUID('8a885d04-1ceb-11c9-9fe8-08002b104860')
uuidNDR64 = uuid.UUID('71710533-beba-4937-8319-b5dbef9ccc36')
uuidTime = uuid.UUID('6cb71c2c-9812-4540-0300-000000000000')
uuidEmpty = uuid.UUID('00000000-0000-0000-0000-000000000000')
class CtxItem(Structure):
structure = (
('ContextID', '<H=0'),
('TransItems', 'B=0'),
('Pad', 'B=0'),
('AbstractSyntaxUUID', '16s=""'),
('AbstractSyntaxVer', '<I=0'),
('TransferSyntaxUUID', '16s=""'),
('TransferSyntaxVer', '<I=0'),
)
def ts(self):
return uuid.UUID(bytes_le=self['TransferSyntaxUUID'].encode('latin-1')) #*2to3*
class CtxItemResult(Structure):
structure = (
('Result', '<H=0'),
('Reason', '<H=0'),
('TransferSyntaxUUID', '16s=""'),
('TransferSyntaxVer', '<I=0'),
)
def __init__(self, result, reason, tsUUID, tsVer):
Structure.__init__(self)
self['Result'] = result
self['Reason'] = reason
self['TransferSyntaxUUID'] = tsUUID.bytes_le
self['TransferSyntaxVer'] = tsVer
class MSRPCBind(Structure):
class CtxItemArray:
def __init__(self, data):
self.data = data
def __len__(self):
return len(self.data)
def __str__(self):
return self.data
def __getitem__(self, i):
return CtxItem(self.data[(len(CtxItem()) * i):])
_CTX_ITEM_LEN = len(CtxItem())
structure = (
('max_tfrag', '<H=4280'),
('max_rfrag', '<H=4280'),
('assoc_group', '<L=0'),
('ctx_num', 'B=0'),
('Reserved', 'B=0'),
('Reserved2', '<H=0'),
('_ctx_items', '_-ctx_items', 'self["ctx_num"]*self._CTX_ITEM_LEN'),
('ctx_items', ':', CtxItemArray),
)
class handler(rpcBase.rpcBase):
def parseRequest(self):
request = MSRPCHeader(self.data)
shell_message(nshell = 3)
request = byterize(request)
logging.debug("RPC Bind Request Bytes: \n%s\n" % justify(binascii.b2a_hex(self.data).decode('utf-8')))
logging.debug("RPC Bind Request: \n%s\n%s\n" % (justify(request.dump(print_to_stdout = False)),
justify(MSRPCBind(request['pduData']).dump(print_to_stdout = False))))
return request
def generateResponse(self):
response = MSRPCBindAck()
request = self.requestData
bind = MSRPCBind(request['pduData'])
response['ver_major'] = request['ver_major']
response['ver_minor'] = request['ver_minor']
response['type'] = self.packetType['bindAck']
response['flags'] = self.packetFlags['firstFrag'] | self.packetFlags['lastFrag'] | self.packetFlags['multiplex']
response['representation'] = request['representation']
response['frag_len'] = 36 + bind['ctx_num'] * 24
response['auth_len'] = request['auth_len']
response['call_id'] = request['call_id']
response['max_tfrag'] = bind['max_tfrag']
response['max_rfrag'] = bind['max_rfrag']
response['assoc_group'] = 0x1063bf3f
port = str(self.config['port'])
response['SecondaryAddrLen'] = len(port) + 1
response['SecondaryAddr'] = port
pad = (4 - ((response["SecondaryAddrLen"] + MSRPCBindAck._SIZE) % 4)) % 4
response['Pad'] = '\0' * pad
response['ctx_num'] = bind['ctx_num']
preparedResponses = {}
preparedResponses[uuidNDR32] = CtxItemResult(0, 0, uuidNDR32, 2)
preparedResponses[uuidNDR64] = CtxItemResult(2, 2, uuidEmpty, 0)
preparedResponses[uuidTime] = CtxItemResult(3, 3, uuidEmpty, 0)
response['ctx_items'] = ''
for i in range (0, bind['ctx_num']):
ts_uuid = bind['ctx_items'][i].ts()
resp = preparedResponses[ts_uuid]
response['ctx_items'] += str(resp)
shell_message(nshell = 4)
response = byterize(response)
logging.debug("RPC Bind Response: \n%s\n" % justify(response.dump(print_to_stdout = False)))
logging.debug("RPC Bind Response Bytes: \n%s\n" % justify(binascii.b2a_hex(str(response).encode('latin-1')).decode('utf-8'))) #*2to3*
return response
def generateRequest(self):
firstCtxItem = CtxItem()
firstCtxItem['ContextID'] = 0
firstCtxItem['TransItems'] = 1
firstCtxItem['Pad'] = 0
firstCtxItem['AbstractSyntaxUUID'] = uuid.UUID('51c82175-844e-4750-b0d8-ec255555bc06').bytes_le
firstCtxItem['AbstractSyntaxVer'] = 1
firstCtxItem['TransferSyntaxUUID'] = uuidNDR32.bytes_le
firstCtxItem['TransferSyntaxVer'] = 2
secondCtxItem = CtxItem()
secondCtxItem['ContextID'] = 1
secondCtxItem['TransItems'] = 1
secondCtxItem['Pad'] = 0
secondCtxItem['AbstractSyntaxUUID'] = uuid.UUID('51c82175-844e-4750-b0d8-ec255555bc06').bytes_le
secondCtxItem['AbstractSyntaxVer'] = 1
secondCtxItem['TransferSyntaxUUID'] = uuidTime.bytes_le
secondCtxItem['TransferSyntaxVer'] = 1
bind = MSRPCBind()
bind['max_tfrag'] = 5840
bind['max_rfrag'] = 5840
bind['assoc_group'] = 0
bind['ctx_num'] = 2
bind['ctx_items'] = str(bind.CtxItemArray(str(firstCtxItem) + str(secondCtxItem))) #*2to3*
request = MSRPCHeader()
request['ver_major'] = 5
request['ver_minor'] = 0
request['type'] = self.packetType['bindReq']
request['flags'] = self.packetFlags['firstFrag'] | self.packetFlags['lastFrag'] | self.packetFlags['multiplex']
request['call_id'] = self.config['call_id']
request['pduData'] = str(bind)
shell_message(nshell = 0)
bind = byterize(bind)
request = byterize(request)
logging.debug("RPC Bind Request: \n%s\n%s\n" % (justify(request.dump(print_to_stdout = False)),
justify(MSRPCBind(request['pduData']).dump(print_to_stdout = False))))
logging.debug("RPC Bind Request Bytes: \n%s\n" % justify(binascii.b2a_hex(str(request).encode('latin-1')).decode('utf-8'))) #*2to3*
return request
def parseResponse(self):
return response

72
py3-kms/rpcRequest.py Normal file
View File

@ -0,0 +1,72 @@
#!/usr/bin/env python3
import binascii
import logging
import struct
import uuid
from dcerpc import MSRPCRequestHeader, MSRPCRespHeader
import kmsBase
import rpcBase
from formatText import justify, shell_message, byterize
class handler(rpcBase.rpcBase):
def parseRequest(self):
request = MSRPCRequestHeader(self.data)
shell_message(nshell = 14)
request = byterize(request)
logging.debug("RPC Message Request Bytes: \n%s\n" % justify(binascii.b2a_hex(self.data).decode('utf-8')))
logging.debug("RPC Message Request: \n%s\n" % justify(request.dump(print_to_stdout = False)))
return request
def generateResponse(self):
request = self.requestData
responseData = kmsBase.generateKmsResponseData(request['pduData'], self.config)
envelopeLength = len(responseData)
response = MSRPCRespHeader()
response['ver_major'] = request['ver_major']
response['ver_minor'] = request['ver_minor']
response['type'] = self.packetType['response']
response['flags'] = self.packetFlags['firstFrag'] | self.packetFlags['lastFrag']
response['representation'] = request['representation']
response['call_id'] = request['call_id']
response['alloc_hint'] = envelopeLength
response['ctx_id'] = request['ctx_id']
response['cancel_count'] = 0
response['pduData'] = responseData
shell_message(nshell = 17)
response = byterize(response)
logging.debug("RPC Message Response: \n%s\n" % justify(response.dump(print_to_stdout = False)))
logging.debug("RPC Message Response Bytes: \n%s\n" % justify(binascii.b2a_hex(str(response).encode('latin-1')).decode('utf-8'))) #*2to3*
return response
def generateRequest(self):
request = MSRPCRequestHeader()
request['ver_major'] = 5
request['ver_minor'] = 0
request['type'] = self.packetType['request']
request['flags'] = self.packetFlags['firstFrag'] | self.packetFlags['lastFrag']
request['representation'] = 0x10
request['call_id'] = self.config['call_id']
request['alloc_hint'] = len(self.data)
request['pduData'] = str(self.data)
shell_message(nshell = 11)
request = byterize(request)
logging.debug("RPC Message Request: \n%s\n" % justify(request.dump(print_to_stdout = False)))
logging.debug("RPC Message Request Bytes: \n%s\n" % justify(binascii.b2a_hex(str(request).encode('latin-1')).decode('utf-8'))) #*2to3*
return request
def parseResponse(self):
return response

135
py3-kms/server.py Normal file
View File

@ -0,0 +1,135 @@
#!/usr/bin/env python3
import argparse
import binascii
import hashlib
import random
import re
import socket
import socketserver
import struct
import uuid
import logging
import os
import rpcBind, rpcRequest
from dcerpc import MSRPCHeader
from rpcBase import rpcBase
from formatText import shell_message
config = {}
def main():
parser = argparse.ArgumentParser(description='py3-kms: KMS Server Emulator written in Python3', epilog="version: py3-kms_2018-03-01")
parser.add_argument("ip", nargs="?", action="store", default="0.0.0.0",
help='The IP address to listen on. The default is \"0.0.0.0\" (all interfaces).', type=str)
parser.add_argument("port", nargs="?", action="store", default=1688,
help='The network port to listen on. The default is \"1688\".', type=int)
parser.add_argument("-e", "--epid", dest="epid", default=None,
help='Use this flag to manually specify an ePID to use. If no ePID is specified, a random ePID will be generated.', type=str)
parser.add_argument("-l", "--lcid", dest="lcid", default=1033,
help='Use this flag to manually specify an LCID for use with randomly generated ePIDs. If an ePID is manually specified,\
this setting is ignored.', type=int)
parser.add_argument("-c", "--client-count", dest="CurrentClientCount", default=26,
help='Use this flag to specify the current client count. Default is 26. A number >25 is required to enable activation.', type=int)
parser.add_argument("-a", "--activation-interval", dest="VLActivationInterval", default=120,
help='Use this flag to specify the activation interval (in minutes). Default is 120 minutes (2 hours).', type=int)
parser.add_argument("-r", "--renewal-interval", dest="VLRenewalInterval", default=1440 * 7,
help='Use this flag to specify the renewal interval (in minutes). Default is 10080 minutes (7 days).', type=int)
parser.add_argument("-s", "--sqlite", dest="sqlite", action="store_const", const=True, default=False,
help='Use this flag to store request information from unique clients in an SQLite database.')
parser.add_argument("-w", "--hwid", dest="hwid", action="store", default='364F463A8863D35F',
help='Use this flag to specify a HWID. The HWID must be an 16-character string of hex characters. \
The default is \"364F463A8863D35F\" or type \"random\" to auto generate the HWID.', type=str)
parser.add_argument("-v", "--loglevel", dest="loglevel", action="store", default="ERROR", choices=["CRITICAL", "ERROR", "WARNING", "INFO", "DEBUG"],
help='Use this flag to set a Loglevel. The default is \"ERROR\".', type=str)
parser.add_argument("-f", "--logfile", dest="logfile", action="store", default=os.path.dirname(os.path.abspath( __file__ )) + "/py3kms_server.log",
help='Use this flag to set an output Logfile. The default is \"pykms_server.log\".', type=str)
config.update(vars(parser.parse_args()))
# Random HWID.
if config['hwid'] == "random":
randomhwid = uuid.uuid4().hex
config['hwid'] = randomhwid[:16]
# Sanitize HWID.
try:
config['hwid'] = binascii.a2b_hex(re.sub(r'[^0-9a-fA-F]', '', config['hwid'].strip('0x')))
if len(binascii.b2a_hex(config['hwid'])) < 16:
logging.error("HWID \"%s\" is invalid. Hex string is too short." % binascii.b2a_hex(config['hwid']).decode('utf-8').upper())
return
elif len(binascii.b2a_hex(config['hwid'])) > 16:
logging.error("HWID \"%s\" is invalid. Hex string is too long." % binascii.b2a_hex(config['hwid']).decode('utf-8').upper())
return
except TypeError:
logging.error("HWID \"%s\" is invalid. Odd-length hex string." % binascii.b2a_hex(config['hwid']).decode('utf-8').upper())
return
logging.basicConfig(level=config['loglevel'], format='%(asctime)s %(levelname)-8s %(message)s',
datefmt='%a, %d %b %Y %H:%M:%S', filename=config['logfile'], filemode='w')
try:
import sqlite3
config['dbSupport'] = True
except:
logging.warning("Module \"sqlite3\" is not installed, database support disabled.")
config['dbSupport'] = False
server = socketserver.TCPServer((config['ip'], config['port']), kmsServer)
server.timeout = 5
logging.info("TCP server listening at %s on port %d." % (config['ip'], config['port']))
logging.info("HWID: %s" % binascii.b2a_hex(config['hwid']).decode('utf-8').upper())
server.serve_forever()
class kmsServer(socketserver.BaseRequestHandler):
def setup(self):
self.connection = self.request
logging.info("Connection accepted: %s:%d" % (self.client_address[0], self.client_address[1]))
def handle(self):
while True:
# self.request is the TCP socket connected to the client
try:
self.data = self.connection.recv(1024)
except socket.error as e: #*2to3*
if e[0] == 104:
logging.error("Connection reset by peer.")
break
else:
raise
if self.data == '' or not self.data:
logging.warning("No data received !")
break
# self.data = bytearray(self.data.strip())
# logging.debug(binascii.b2a_hex(str(self.data)))
packetType = MSRPCHeader(self.data)['type']
if packetType == rpcBase.packetType['bindReq']:
logging.info("RPC bind request received.")
shell_message(nshell = [-2, 2])
handler = rpcBind.handler(self.data, config)
elif packetType == rpcBase.packetType['request']:
logging.info("Received activation request.")
shell_message(nshell = [-2, 13])
handler = rpcRequest.handler(self.data, config)
else:
logging.error("Invalid RPC request type ", packetType)
break
handler.populate()
res = str(handler.getResponse()).encode('latin-1') #*2to3*
self.connection.send(res)
if packetType == rpcBase.packetType['bindReq']:
logging.info("RPC bind acknowledged.")
shell_message(nshell = [-3, 5, 6])
elif packetType == rpcBase.packetType['request']:
logging.info("Responded to activation request.")
shell_message(nshell = [-3, 18, 19])
break
def finish(self):
self.connection.close()
logging.info("Connection closed: %s:%d" % (self.client_address[0], self.client_address[1]))
if __name__ == "__main__":
main()

793
py3-kms/structure.py Normal file
View File

@ -0,0 +1,793 @@
#!/usr/bin/env python3
# Copyright (c) 2003-2012 CORE Security Technologies
#
# This software is provided under under a slightly modified version
# of the Apache Software License. See the accompanying LICENSE file
# for more information.
#
""" Version of https://github.com/CoreSecurity/impacket/blob/python3/impacket/structure.py
with modifications in the function dump(...).
© Copyright 2018 Matteo an <SystemRage@protonmail.com>
"""
from struct import pack, unpack, calcsize
# Trying to support both Python 2 and 3
import sys
if sys.version_info[0] == 2:
# Python 2.x
def b(x):
return x
def buildStr(x):
return x
else:
import codecs
def b(x):
if isinstance(x, bytes) is False:
return codecs.latin_1_encode(x)[0]
return x
def buildStr(x):
if isinstance(x, bytes):
return "".join(map(chr,x))
else:
return x
class Structure:
""" sublcasses can define commonHdr and/or structure.
each of them is an tuple of either two: (fieldName, format) or three: (fieldName, ':', class) fields.
[it can't be a dictionary, because order is important]
where format specifies how the data in the field will be converted to/from bytes (string)
class is the class to use when unpacking ':' fields.
each field can only contain one value (or an array of values for *)
i.e. struct.pack('Hl',1,2) is valid, but format specifier 'Hl' is not (you must use 2 dfferent fields)
format specifiers:
specifiers from module pack can be used with the same format
see struct.__doc__ (pack/unpack is finally called)
x [padding byte]
c [character]
b [signed byte]
B [unsigned byte]
h [signed short]
H [unsigned short]
l [signed long]
L [unsigned long]
i [signed integer]
I [unsigned integer]
q [signed long long (quad)]
Q [unsigned long long (quad)]
s [string (array of chars), must be preceded with length in format specifier, padded with zeros]
p [pascal string (includes byte count), must be preceded with length in format specifier, padded with zeros]
f [float]
d [double]
= [native byte ordering, size and alignment]
@ [native byte ordering, standard size and alignment]
! [network byte ordering]
< [little endian]
> [big endian]
usual printf like specifiers can be used (if started with %)
[not recommeneded, there is no why to unpack this]
%08x will output an 8 bytes hex
%s will output a string
%s\\x00 will output a NUL terminated string
%d%d will output 2 decimal digits (against the very same specification of Structure)
...
some additional format specifiers:
: just copy the bytes from the field into the output string (input may be string, other structure, or anything responding to __str__()) (for unpacking, all what's left is returned)
z same as :, but adds a NUL byte at the end (asciiz) (for unpacking the first NUL byte is used as terminator) [asciiz string]
u same as z, but adds two NUL bytes at the end (after padding to an even size with NULs). (same for unpacking) [unicode string]
w DCE-RPC/NDR string (it's a macro for [ '<L=(len(field)+1)/2','"\\x00\\x00\\x00\\x00','<L=(len(field)+1)/2',':' ]
?-field length of field named 'field', formated as specified with ? ('?' may be '!H' for example). The input value overrides the real length
?1*?2 array of elements. Each formated as '?2', the number of elements in the array is stored as specified by '?1' (?1 is optional, or can also be a constant (number), for unpacking)
'xxxx literal xxxx (field's value doesn't change the output. quotes must not be closed or escaped)
"xxxx literal xxxx (field's value doesn't change the output. quotes must not be closed or escaped)
_ will not pack the field. Accepts a third argument, which is an unpack code. See _Test_UnpackCode for an example
?=packcode will evaluate packcode in the context of the structure, and pack the result as specified by ?. Unpacking is made plain
?&fieldname "Address of field fieldname".
For packing it will simply pack the id() of fieldname. Or use 0 if fieldname doesn't exists.
For unpacking, it's used to know weather fieldname has to be unpacked or not, i.e. by adding a & field you turn another field (fieldname) in an optional field.
"""
commonHdr = ()
structure = ()
debug = 0
def __init__(self, data = None, alignment = 0):
if not hasattr(self, 'alignment'):
self.alignment = alignment
self.fields = {}
self.rawData = data
if data is not None:
self.fromString(data)
else:
self.data = None
@classmethod
def fromFile(self, file):
answer = self()
answer.fromString(file.read(len(answer)))
return answer
def setAlignment(self, alignment):
self.alignment = alignment
def setData(self, data):
self.data = data
def packField(self, fieldName, format = None):
if self.debug:
print("packField( %s | %s )" % (fieldName, format))
if format is None:
format = self.formatForField(fieldName)
if fieldName in self.fields:
ans = self.pack(format, self.fields[fieldName], field = fieldName)
else:
ans = self.pack(format, None, field = fieldName)
if self.debug:
print("\tanswer %r" % ans)
return ans
def getData(self):
if self.data is not None:
return self.data
data = b''
for field in self.commonHdr+self.structure:
try:
data += b(self.packField(field[0], field[1]))
except Exception as e:
if field[0] in self.fields:
e.args += ("When packing field '%s | %s | %r' in %s" % (field[0], field[1], self[field[0]], self.__class__),)
else:
e.args += ("When packing field '%s | %s' in %s" % (field[0], field[1], self.__class__),)
raise
if self.alignment:
if len(data) % self.alignment:
data += b('\x00'*self.alignment)[:-(len(data) % self.alignment)]
#if len(data) % self.alignment: data += ('\x00'*self.alignment)[:-(len(data) % self.alignment)]
if isinstance(data,str):
return data
return buildStr(data)
def fromString(self, data):
self.rawData = data
data = buildStr(data)
for field in self.commonHdr+self.structure:
if self.debug:
print("fromString( %s | %s | %r )" % (field[0], field[1], data))
size = self.calcUnpackSize(field[1], data, field[0])
if self.debug:
print(" size = %d" % size)
dataClassOrCode = str
if len(field) > 2:
dataClassOrCode = field[2]
try:
self[field[0]] = self.unpack(field[1], data[:size], dataClassOrCode = dataClassOrCode, field = field[0])
except Exception as e:
e.args += ("When unpacking field '%s | %s | %r[:%d]'" % (field[0], field[1], data, size),)
raise
size = self.calcPackSize(field[1], self[field[0]], field[0])
if self.alignment and size % self.alignment:
size += self.alignment - (size % self.alignment)
data = data[size:]
return self
def __setitem__(self, key, value):
self.fields[key] = value
self.data = None # force recompute
def __getitem__(self, key):
return self.fields[key]
def __delitem__(self, key):
del self.fields[key]
def __str__(self):
return self.getData()
def __len__(self):
# XXX: improve
return len(self.getData())
def pack(self, format, data, field = None):
if self.debug:
print(" pack( %s | %r | %s)" % (format, data, field))
if field:
addressField = self.findAddressFieldFor(field)
if (addressField is not None) and (data is None):
return b''
# void specifier
if format[:1] == '_':
return b''
# quote specifier
if format[:1] == "'" or format[:1] == '"':
return b(format[1:])
# code specifier
two = format.split('=')
if len(two) >= 2:
try:
return self.pack(two[0], data)
except:
fields = {'self':self}
fields.update(self.fields)
return self.pack(two[0], eval(two[1], {}, fields))
# address specifier
two = format.split('&')
if len(two) == 2:
try:
return self.pack(two[0], data)
except:
if (two[1] in self.fields) and (self[two[1]] is not None):
return self.pack(two[0], id(self[two[1]]) & ((1<<(calcsize(two[0])*8))-1) )
else:
return self.pack(two[0], 0)
# length specifier
two = format.split('-')
if len(two) == 2:
try:
return self.pack(two[0],data)
except:
return self.pack(two[0], self.calcPackFieldSize(two[1]))
# array specifier
two = format.split('*')
if len(two) == 2:
answer = b''
for each in data:
answer += self.pack(two[1], each)
if two[0]:
if two[0].isdigit():
if int(two[0]) != len(data):
raise Exception("Array field has a constant size, and it doesn't match the actual value")
else:
return self.pack(two[0], len(data))+answer
return answer
# "printf" string specifier
if format[:1] == '%':
# format string like specifier
return format % data
# asciiz specifier
if format[:1] == 'z':
return b(data)+b'\0'
# unicode specifier
if format[:1] == 'u':
return b(data)+b'\0\0' + (len(data) & 1 and b'\0' or b'')
# DCE-RPC/NDR string specifier
if format[:1] == 'w':
if len(data) == 0:
data = '\0\0'
elif len(data) % 2:
data += '\0'
l = pack('<L', int(len(data)/2))
l = buildStr(l)
return b('%s\0\0\0\0%s%s' % (l,l,data))
if data is None:
raise Exception("Trying to pack None")
# literal specifier
if format[:1] == ':':
# Inner Structures?
if isinstance(data,Structure):
return b(data.getData())
return b(data)
# struct like specifier
if isinstance(data, str):
return pack(format, b(data))
else:
return pack(format, data)
def unpack(self, format, data, dataClassOrCode = str, field = None):
if self.debug:
print(" unpack( %s | %r )" % (format, data))
if field:
addressField = self.findAddressFieldFor(field)
if addressField is not None:
if not self[addressField]:
return
# void specifier
if format[:1] == '_':
if dataClassOrCode != str:
fields = {'self':self, 'inputDataLeft':data}
fields.update(self.fields)
return eval(dataClassOrCode, {}, fields)
else:
return None
# quote specifier
if format[:1] == "'" or format[:1] == '"':
answer = format[1:]
if answer != data:
raise Exception("Unpacked data doesn't match constant value '%r' should be '%r'" % (data, answer))
return answer
# address specifier
two = format.split('&')
if len(two) == 2:
return self.unpack(two[0],data)
# code specifier
two = format.split('=')
if len(two) >= 2:
return self.unpack(two[0],data)
# length specifier
two = format.split('-')
if len(two) == 2:
return self.unpack(two[0],data)
# array specifier
two = format.split('*')
if len(two) == 2:
answer = []
sofar = 0
if two[0].isdigit():
number = int(two[0])
elif two[0]:
sofar += self.calcUnpackSize(two[0], data)
number = self.unpack(two[0], data[:sofar])
else:
number = -1
while number and sofar < len(data):
nsofar = sofar + self.calcUnpackSize(two[1],data[sofar:])
answer.append(self.unpack(two[1], data[sofar:nsofar], dataClassOrCode))
number -= 1
sofar = nsofar
return answer
# "printf" string specifier
if format[:1] == '%':
# format string like specifier
return format % data
# asciiz specifier
if format == 'z':
if data[-1] != '\x00':
raise Exception("%s 'z' field is not NUL terminated: %r" % (field, data))
return data[:-1] # remove trailing NUL
# unicode specifier
if format == 'u':
if data[-2:] != '\x00\x00':
raise Exception("%s 'u' field is not NUL-NUL terminated: %r" % (field, data))
return data[:-2] # remove trailing NUL
# DCE-RPC/NDR string specifier
if format == 'w':
l = unpack('<L', b(data[:4]))[0]
return data[12:12+l*2]
# literal specifier
if format == ':':
return dataClassOrCode(data)
# struct like specifier
if format.find('s') >=0:
return buildStr(unpack(format, b(data))[0])
else:
return unpack(format, b(data))[0]
def calcPackSize(self, format, data, field = None):
#print( " calcPackSize %s:%r" % (format, data))
if field:
addressField = self.findAddressFieldFor(field)
if addressField is not None:
if not self[addressField]:
return 0
# void specifier
if format[:1] == '_':
return 0
# quote specifier
if format[:1] == "'" or format[:1] == '"':
return len(format)-1
# address specifier
two = format.split('&')
if len(two) == 2:
return self.calcPackSize(two[0], data)
# code specifier
two = format.split('=')
if len(two) >= 2:
return self.calcPackSize(two[0], data)
# length specifier
two = format.split('-')
if len(two) == 2:
return self.calcPackSize(two[0], data)
# array specifier
two = format.split('*')
if len(two) == 2:
answer = 0
if two[0].isdigit():
if int(two[0]) != len(data):
raise Exception("Array field has a constant size, and it doesn't match the actual value")
elif two[0]:
answer += self.calcPackSize(two[0], len(data))
for each in data:
answer += self.calcPackSize(two[1], each)
return answer
# "printf" string specifier
if format[:1] == '%':
# format string like specifier
return len(format % data)
# asciiz specifier
if format[:1] == 'z':
return len(data)+1
# asciiz specifier
if format[:1] == 'u':
l = len(data)
return l + (l & 1 and 3 or 2)
# DCE-RPC/NDR string specifier
if format[:1] == 'w':
l = len(data)
return int((12+l+(l % 2)))
# literal specifier
if format[:1] == ':':
return len(data)
# struct like specifier
return calcsize(format)
def calcUnpackSize(self, format, data, field = None):
if self.debug:
print(" calcUnpackSize( %s | %s | %r)" % (field, format, data))
# void specifier
if format[:1] == '_':
return 0
addressField = self.findAddressFieldFor(field)
if addressField is not None:
if not self[addressField]:
return 0
try:
lengthField = self.findLengthFieldFor(field)
return int(self[lengthField])
except:
pass
# XXX: Try to match to actual values, raise if no match
# quote specifier
if format[:1] == "'" or format[:1] == '"':
return len(format)-1
# address specifier
two = format.split('&')
if len(two) == 2:
return self.calcUnpackSize(two[0], data)
# code specifier
two = format.split('=')
if len(two) >= 2:
return self.calcUnpackSize(two[0], data)
# length specifier
two = format.split('-')
if len(two) == 2:
return self.calcUnpackSize(two[0], data)
# array specifier
two = format.split('*')
if len(two) == 2:
answer = 0
if two[0]:
if two[0].isdigit():
number = int(two[0])
else:
answer += self.calcUnpackSize(two[0], data)
number = self.unpack(two[0], data[:answer])
while number:
number -= 1
answer += self.calcUnpackSize(two[1], data[answer:])
else:
while answer < len(data):
answer += self.calcUnpackSize(two[1], data[answer:])
return answer
# "printf" string specifier
if format[:1] == '%':
raise Exception("Can't guess the size of a printf like specifier for unpacking")
# asciiz specifier
if format[:1] == 'z':
return data.index('\x00')+1
# asciiz specifier
if format[:1] == 'u':
l = data.index('\x00\x00')
return l + (l & 1 and 3 or 2)
# DCE-RPC/NDR string specifier
if format[:1] == 'w':
l = unpack('<L', b(data[:4]))[0]
return 12+l*2
# literal specifier
if format[:1] == ':':
return len(data)
# struct like specifier
return calcsize(format)
def calcPackFieldSize(self, fieldName, format = None):
if format is None:
format = self.formatForField(fieldName)
return self.calcPackSize(format, self[fieldName])
def formatForField(self, fieldName):
for field in self.commonHdr+self.structure:
if field[0] == fieldName:
return field[1]
raise Exception("Field %s not found" % fieldName)
def findAddressFieldFor(self, fieldName):
descriptor = '&%s' % fieldName
l = len(descriptor)
for field in self.commonHdr+self.structure:
if field[1][-l:] == descriptor:
return field[0]
return None
def findLengthFieldFor(self, fieldName):
descriptor = '-%s' % fieldName
l = len(descriptor)
for field in self.commonHdr+self.structure:
if field[1][-l:] == descriptor:
return field[0]
return None
def zeroValue(self, format):
two = format.split('*')
if len(two) == 2:
if two[0].isdigit():
return (self.zeroValue(two[1]),)*int(two[0])
if not format.find('*') == -1: return ()
if 's' in format: return b''
if format in ['z',':','u']: return ''
if format == 'w': return b'\x00\x00'
return 0
def clear(self):
for field in self.commonHdr + self.structure:
self[field[0]] = self.zeroValue(field[1])
def dump(self, msg = None, indent = 0, print_to_stdout = True):
if msg is None:
msg = self.__class__.__name__
ind = ' '*indent
allstr = "\n%s" % msg
fixedFields = []
for field in self.commonHdr+self.structure:
i = field[0]
if i in self.fields:
fixedFields.append(i)
if isinstance(self[i], Structure):
tempstr = self[i].dump('%s%s:{' % (ind, i), indent = indent + 4, print_to_stdout = False)
allstr += tempstr + "\n%s}" % ind
else:
allstr += "\n%s%s: {%r}" % (ind, i, self[i])
# Do we have remaining fields not defined in the structures? let's
# print them.
remainingFields = list(set(self.fields) - set(fixedFields))
for i in remainingFields:
if isinstance(self[i], Structure):
tempstr = self[i].dump('%s%s:{' % (ind, i), indent = indent + 4, print_to_stdout = False)
allstr += tempstr + "\n%s}" % ind
else:
allstr += "\n%s%s: {%r}" % (ind, i, self[i])
# Finish job.
if not print_to_stdout:
# print(allstr) # Uncomment this line only for view that test is OK with "print_to_stdout = False".
return allstr
else:
print(allstr)
class _StructureTest:
alignment = 0
def create(self,data = None):
if data is not None:
return self.theClass(data, alignment = self.alignment)
else:
return self.theClass(alignment = self.alignment)
def run(self):
print()
print("-"*70)
testName = self.__class__.__name__
print("starting test: %s....." % testName)
a = self.create()
self.populate(a)
a.dump("packing.....")
a_str = a.getData()
print("packed: %r, %d" % (a_str,len(a_str)))
print("unpacking.....")
b = self.create(a_str)
b.dump("unpacked.....")
print("repacking.....")
b_str = b.getData()
if b_str != a_str:
print("ERROR: original packed and repacked don't match")
print("packed: %r" % b_str)
class _Test_simple(_StructureTest):
class theClass(Structure):
commonHdr = ()
structure = (
('int1', '!L'),
('len1','!L-z1'),
('arr1','B*<L'),
('z1', 'z'),
('u1','u'),
('', '"COCA'),
('len2','!H-:1'),
('', '"COCA'),
(':1', ':'),
('int3','>L'),
('code1','>L=len(arr1)*2+0x1000'),
)
def populate(self, a):
a['default'] = 'hola'
a['int1'] = 0x3131
a['int3'] = 0x45444342
a['z1'] = 'hola'
a['u1'] = 'hola'.encode('utf_16_le')
a[':1'] = ':1234:'
a['arr1'] = (0x12341234,0x88990077,0x41414141)
# a['len1'] = 0x42424242
class _Test_fixedLength(_Test_simple):
def populate(self, a):
_Test_simple.populate(self, a)
a['len1'] = 0x42424242
class _Test_simple_aligned4(_Test_simple):
alignment = 4
class _Test_nested(_StructureTest):
class theClass(Structure):
class _Inner(Structure):
structure = (('data', 'z'),)
structure = (
('nest1', ':', _Inner),
('nest2', ':', _Inner),
('int', '<L'),
)
def populate(self, a):
a['nest1'] = _Test_nested.theClass._Inner()
a['nest2'] = _Test_nested.theClass._Inner()
a['nest1']['data'] = 'hola manola'
a['nest2']['data'] = 'chau loco'
a['int'] = 0x12345678
class _Test_Optional(_StructureTest):
class theClass(Structure):
structure = (
('pName','<L&Name'),
('pList','<L&List'),
('Name','w'),
('List','<H*<L'),
)
def populate(self, a):
a['Name'] = 'Optional test'
a['List'] = (1,2,3,4)
class _Test_Optional_sparse(_Test_Optional):
def populate(self, a):
_Test_Optional.populate(self, a)
del a['Name']
class _Test_AsciiZArray(_StructureTest):
class theClass(Structure):
structure = (
('head','<L'),
('array','B*z'),
('tail','<L'),
)
def populate(self, a):
a['head'] = 0x1234
a['tail'] = 0xabcd
a['array'] = ('hola','manola','te traje')
class _Test_UnpackCode(_StructureTest):
class theClass(Structure):
structure = (
('leni','<L=len(uno)*2'),
('cuchi','_-uno','leni/2'),
('uno',':'),
('dos',':'),
)
def populate(self, a):
a['uno'] = 'soy un loco!'
a['dos'] = 'que haces fiera'
class _Test_AAA(_StructureTest):
class theClass(Structure):
commonHdr = ()
structure = (
('iv', '!L=((init_vector & 0xFFFFFF) << 8) | ((pad & 0x3f) << 2) | (keyid & 3)'),
('init_vector', '_','(iv >> 8)'),
('pad', '_','((iv >>2) & 0x3F)'),
('keyid', '_','( iv & 0x03 )'),
('dataLen', '_-data', 'len(inputDataLeft)-4'),
('data',':'),
('icv','>L'),
)
def populate(self, a):
a['init_vector']=0x01020304
#a['pad']=int('01010101',2)
a['pad']=int('010101',2)
a['keyid']=0x07
a['data']="\xA0\xA1\xA2\xA3\xA4\xA5\xA6\xA7\xA8\xA9"
a['icv'] = 0x05060708
#a['iv'] = 0x01020304
if __name__ == '__main__':
_Test_simple().run()
try:
_Test_fixedLength().run()
except:
print("cannot repack because length is bogus")
_Test_simple_aligned4().run()
_Test_nested().run()
_Test_Optional().run()
_Test_Optional_sparse().run()
_Test_AsciiZArray().run()
_Test_UnpackCode().run()
_Test_AAA().run()

263
py3-kms/timezones.py Normal file
View File

@ -0,0 +1,263 @@
#!/usr/bin/env python3
# vim: set ts=2 sw=2 et sts=2 ai:
#
# Copyright 2009 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# Disable the invalid name warning as we are inheriting from a standard library
# object.
# pylint: disable=invalid-name,protected-access
"""
Stripped down version of `python-datetime-tz`
( https://github.com/mithro/python-datetime-tz/blob/master/datetime_tz/__init__.py )
that only contains the "find local timezone" bits.
"""
import datetime
import os.path
import time
import warnings
import pytz
# Need to patch pytz.utc to have a _utcoffset so you can normalize/localize
# using it.
pytz.utc._utcoffset = datetime.timedelta()
timedelta = datetime.timedelta
def _tzinfome(tzinfo):
"""Gets a tzinfo object from a string.
Args:
tzinfo: A string (or string like) object, or a datetime.tzinfo object.
Returns:
An datetime.tzinfo object.
Raises:
UnknownTimeZoneError: If the timezone given can't be decoded.
"""
if not isinstance(tzinfo, datetime.tzinfo):
try:
tzinfo = pytz.timezone(tzinfo)
assert tzinfo.zone in pytz.all_timezones
except AttributeError:
raise pytz.UnknownTimeZoneError("Unknown timezone! %s" % tzinfo)
return tzinfo
# Our "local" timezone
_localtz = None
def localtz():
"""Get the local timezone.
Returns:
The localtime timezone as a tzinfo object.
"""
# pylint: disable=global-statement
global _localtz
if _localtz is None:
_localtz = detect_timezone()
return _localtz
def detect_timezone():
"""Try and detect the timezone that Python is currently running in.
We have a bunch of different methods for trying to figure this out (listed in
order they are attempted).
* In windows, use win32timezone.TimeZoneInfo.local()
* Try TZ environment variable.
* Try and find /etc/timezone file (with timezone name).
* Try and find /etc/localtime file (with timezone data).
* Try and match a TZ to the current dst/offset/shortname.
Returns:
The detected local timezone as a tzinfo object
Raises:
pytz.UnknownTimeZoneError: If it was unable to detect a timezone.
"""
# First we try the TZ variable
tz = _detect_timezone_environ()
if tz is not None:
return tz
# Second we try /etc/timezone and use the value in that
tz = _detect_timezone_etc_timezone()
if tz is not None:
return tz
# Next we try and see if something matches the tzinfo in /etc/localtime
tz = _detect_timezone_etc_localtime()
if tz is not None:
return tz
# Next we try and use a similiar method to what PHP does.
# We first try to search on time.tzname, time.timezone, time.daylight to
# match a pytz zone.
warnings.warn("Had to fall back to worst detection method (the 'PHP' "
"method).")
tz = _detect_timezone_php()
if tz is not None:
return tz
raise pytz.UnknownTimeZoneError("Unable to detect your timezone!")
def _detect_timezone_environ():
if "TZ" in os.environ:
try:
return pytz.timezone(os.environ["TZ"])
except (IOError, pytz.UnknownTimeZoneError):
warnings.warn("You provided a TZ environment value (%r) we did not "
"understand!" % os.environ["TZ"])
def _detect_timezone_etc_timezone():
if os.path.exists("/etc/timezone"):
try:
tz = open("/etc/timezone").read().strip()
try:
return pytz.timezone(tz)
except (IOError, pytz.UnknownTimeZoneError) as ei:
warnings.warn("Your /etc/timezone file references a timezone (%r) that"
" is not valid (%r)." % (tz, ei))
# Problem reading the /etc/timezone file
except IOError as eo:
warnings.warn("Could not access your /etc/timezone file: %s" % eo)
def _load_local_tzinfo():
"""Load zoneinfo from local disk."""
tzdir = os.environ.get("TZDIR", "/usr/share/zoneinfo/posix")
localtzdata = {}
for dirpath, _, filenames in os.walk(tzdir):
for filename in filenames:
filepath = os.path.join(dirpath, filename)
name = os.path.relpath(filepath, tzdir)
f = open(filepath, "rb")
tzinfo = pytz.tzfile.build_tzinfo(name, f)
f.close()
localtzdata[name] = tzinfo
return localtzdata
def _detect_timezone_etc_localtime():
"""Detect timezone based on /etc/localtime file."""
matches = []
if os.path.exists("/etc/localtime"):
f = open("/etc/localtime", "rb")
localtime = pytz.tzfile.build_tzinfo("/etc/localtime", f)
f.close()
# We want to match against the local database because /etc/localtime will
# be copied from that. Once we have found a name for /etc/localtime, we can
# use the name to get the "same" timezone from the inbuilt pytz database.
tzdatabase = _load_local_tzinfo()
if tzdatabase:
tznames = tzdatabase.keys()
tzvalues = tzdatabase.__getitem__
else:
tznames = pytz.all_timezones
tzvalues = _tzinfome
# See if we can find a "Human Name" for this..
for tzname in tznames:
tz = tzvalues(tzname)
if dir(tz) != dir(localtime):
continue
for attrib in dir(tz):
# Ignore functions and specials
if callable(getattr(tz, attrib)) or attrib.startswith("__"):
continue
# This will always be different
if attrib == "zone" or attrib == "_tzinfos":
continue
if getattr(tz, attrib) != getattr(localtime, attrib):
break
# We get here iff break didn't happen, i.e. no meaningful attributes
# differ between tz and localtime
else:
# Try and get a timezone from pytz which has the same name as the zone
# which matches in the local database.
if tzname not in pytz.all_timezones:
warnings.warn("Skipping %s because not in pytz database." % tzname)
continue
matches.append(_tzinfome(tzname))
matches.sort(key=lambda x: x.zone)
if len(matches) == 1:
return matches[0]
if len(matches) > 1:
warnings.warn("We detected multiple matches for your /etc/localtime. "
"(Matches where %s)" % matches)
return matches[0]
else:
warnings.warn("We detected no matches for your /etc/localtime.")
# Register /etc/localtime as the timezone loaded.
pytz._tzinfo_cache["/etc/localtime"] = localtime
return localtime
def _detect_timezone_php():
tomatch = (time.tzname[0], time.timezone, time.daylight)
now = datetime.datetime.now()
matches = []
for tzname in pytz.all_timezones:
try:
tz = pytz.timezone(tzname)
except IOError:
continue
try:
indst = tz.localize(now).timetuple()[-1]
if tomatch == (tz._tzname, -tz._utcoffset.seconds, indst):
matches.append(tzname)
# pylint: disable=pointless-except
except AttributeError:
pass
if len(matches) > 1:
warnings.warn("We detected multiple matches for the timezone, choosing "
"the first %s. (Matches where %s)" % (matches[0], matches))
if matches:
return pytz.timezone(matches[0])