A Great Update: py-kms_2019-05-15

This commit is contained in:
Matteo ℱan 2019-05-14 22:12:49 +02:00 committed by GitHub
parent 698353f800
commit 660d86d42b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
23 changed files with 6589 additions and 991 deletions

File diff suppressed because it is too large Load diff

739
py-kms/pykms_Aes.py Normal file
View file

@ -0,0 +1,739 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# 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 )
#
# Modified for py-kms, Python 2 / 3 compatible
# Copyright (c) 2019 Matteo Fan ( SystemRage@protonmail.com )
#
# 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/
#
from __future__ import print_function, unicode_literals
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 * bytearray(chr(numpads).encode('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 bytes 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 bytes 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 bytes 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 end > 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 = bytearray(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 + bytearray(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 bytearray(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:', bytes(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 = bytearray(cleartext.encode("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")

255
py-kms/pykms_Base.py Normal file
View file

@ -0,0 +1,255 @@
#!/usr/bin/env python3
import binascii
import logging
import os
import sys
import time
import uuid
import socket
from pykms_Structure import Structure
from pykms_DB2Dict import kmsDB2Dict
from pykms_PidGenerator import epidGenerator
from pykms_Filetimes import filetime_to_dt
from pykms_Sql import sql_initialize, sql_update, sql_update_epid
from pykms_Format import justify, byterize, enco, deco, ShellMessage
#--------------------------------------------------------------------------------------------------------------------------------------------------------
loggersrv = logging.getLogger('logsrv')
class UUID(Structure):
commonHdr = ()
structure = (
('raw', '16s'),
)
def get(self):
return uuid.UUID(bytes_le = enco(str(self), 'latin-1'))
class kmsBase:
def __init__(self, data, srv_config):
self.data = data
self.srv_config = srv_config
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', '_'),
)
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
}
def getPadding(self, bodyLength):
## https://forums.mydigitallife.info/threads/71213-Source-C-KMS-Server-from-Microsoft-Toolkit?p=1277542&viewfull=1#post1277542
return 4 + (((~bodyLength & 3) + 1) & 3)
def serverLogic(self, kmsRequest):
if self.srv_config['sqlite'] and self.srv_config['dbSupport']:
self.dbName = sql_initialize()
ShellMessage.Process(15).run()
kmsRequest = byterize(kmsRequest)
loggersrv.debug("KMS Request Bytes: \n%s\n" % justify(deco(binascii.b2a_hex(enco(str(kmsRequest), 'latin-1')), 'latin-1')))
loggersrv.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 = filetime_to_dt(kmsRequest['requestTime'])
# Localize the request time, if module "tzlocal" is available.
try:
from tzlocal import get_localzone
from pytz.exceptions import UnknownTimeZoneError
try:
tz = get_localzone()
local_dt = tz.localize(requestDatetime)
except UnknownTimeZoneError:
loggersrv.warning('Unknown time zone ! Request time not localized.')
local_dt = requestDatetime
except ImportError:
loggersrv.warning('Module "tzlocal" not available ! Request time not localized.')
local_dt = requestDatetime
# Activation threshold.
# https://docs.microsoft.com/en-us/windows/deployment/volume-activation/activate-windows-10-clients-vamt
MinClients = kmsRequest['requiredClientCount']
RequiredClients = MinClients * 2
if self.srv_config["CurrentClientCount"] != None:
if 0 < self.srv_config["CurrentClientCount"] < MinClients:
# fixed to 6 (product server) or 26 (product desktop)
currentClientCount = MinClients + 1
loggersrv.warning("Not enough clients ! Fixed with %s, but activated client could be detected as not genuine !" %currentClientCount)
elif MinClients <= self.srv_config["CurrentClientCount"] < RequiredClients:
currentClientCount = self.srv_config["CurrentClientCount"]
loggersrv.warning("With count = %s, activated client could be detected as not genuine !" %currentClientCount)
elif self.srv_config["CurrentClientCount"] >= RequiredClients:
# fixed to 10 (product server) or 50 (product desktop)
currentClientCount = RequiredClients
if self.srv_config["CurrentClientCount"] > RequiredClients:
loggersrv.warning("Too many clients ! Fixed with %s" %currentClientCount)
else:
# fixed to 10 (product server) or 50 (product desktop)
currentClientCount = RequiredClients
# Get a name for SkuId, AppId.
kmsdb = kmsDB2Dict()
appitems = kmsdb[2]
for appitem in appitems:
kmsitems = appitem['KmsItems']
for kmsitem in kmsitems:
skuitems = kmsitem['SkuItems']
for skuitem in skuitems:
try:
if uuid.UUID(skuitem['Id']) == skuId:
skuName = skuitem['DisplayName']
break
except:
skuName = skuId
loggersrv.warning("Can't find a name for this product !!")
try:
if uuid.UUID(appitem['Id']) == applicationId:
appName = appitem['DisplayName']
except:
appName = applicationId
loggersrv.warning("Can't find a name for this application group !!")
infoDict = {
"machineName" : kmsRequest.getMachineName(),
"clientMachineId" : str(clientMachineId),
"appId" : appName,
"skuId" : skuName,
"licenseStatus" : kmsRequest.getLicenseStatus(),
"requestTime" : int(time.time()),
"kmsEpid" : None
}
loggersrv.info("Machine Name: %s" % infoDict["machineName"])
loggersrv.info("Client Machine ID: %s" % infoDict["clientMachineId"])
loggersrv.info("Application ID: %s" % infoDict["appId"])
loggersrv.info("SKU ID: %s" % infoDict["skuId"])
loggersrv.info("License Status: %s" % infoDict["licenseStatus"])
loggersrv.info("Request Time: %s" % local_dt.strftime('%Y-%m-%d %H:%M:%S %Z (UTC%z)'))
loggersrv.mini("", extra = {'host': socket.gethostname() + " [" + self.srv_config["ip"] + "]",
'status' : infoDict["licenseStatus"],
'product' : infoDict["skuId"]})
if self.srv_config['sqlite'] and self.srv_config['dbSupport']:
sql_update(self.dbName, infoDict)
return self.createKmsResponse(kmsRequest, currentClientCount)
def createKmsResponse(self, kmsRequest, currentClientCount):
response = self.kmsResponseStruct()
response['versionMinor'] = kmsRequest['versionMinor']
response['versionMajor'] = kmsRequest['versionMajor']
if not self.srv_config["epid"]:
response["kmsEpid"] = epidGenerator(kmsRequest['kmsCountedId'].get(), kmsRequest['versionMajor'],
self.srv_config["lcid"]).encode('utf-16le')
else:
response["kmsEpid"] = self.srv_config["epid"].encode('utf-16le')
response['clientMachineId'] = kmsRequest['clientMachineId']
# rule: timeserver - 4h <= timeclient <= timeserver + 4h, check if is satisfied.
response['responseTime'] = kmsRequest['requestTime']
response['currentClientCount'] = currentClientCount
response['vLActivationInterval'] = self.srv_config["VLActivationInterval"]
response['vLRenewalInterval'] = self.srv_config["VLRenewalInterval"]
if self.srv_config['sqlite'] and self.srv_config['dbSupport']:
response = sql_update_epid(self.dbName, kmsRequest, response)
loggersrv.info("Server ePID: %s" % response["kmsEpid"].decode('utf-16le'))
return response
import pykms_RequestV4, pykms_RequestV5, pykms_RequestV6, pykms_RequestUnknown
def generateKmsResponseData(data, srv_config):
version = kmsBase.GenericRequestHeader(data)['versionMajor']
currentDate = time.strftime("%a %b %d %H:%M:%S %Y")
if version == 4:
loggersrv.info("Received V%d request on %s." % (version, currentDate))
messagehandler = pykms_RequestV4.kmsRequestV4(data, srv_config)
elif version == 5:
loggersrv.info("Received V%d request on %s." % (version, currentDate))
messagehandler = pykms_RequestV5.kmsRequestV5(data, srv_config)
elif version == 6:
loggersrv.info("Received V%d request on %s." % (version, currentDate))
messagehandler = pykms_RequestV6.kmsRequestV6(data, srv_config)
else:
loggersrv.info("Unhandled KMS version V%d." % version)
messagehandler = pykms_RequestUnknown.kmsRequestUnknown(data, srv_config)
return messagehandler.executeRequestLogic()

266
py-kms/pykms_Client.py Normal file
View file

@ -0,0 +1,266 @@
#!/usr/bin/env python3
import re
import argparse
import binascii
import datetime
import random
import socket
import string
import sys
import uuid
import logging
import os
import errno
import pykms_RpcBind, pykms_RpcRequest
from pykms_Filetimes import dt_to_filetime
from pykms_Dcerpc import MSRPCHeader, MSRPCBindNak, MSRPCRequestHeader, MSRPCRespHeader
from pykms_Base import kmsBase, UUID
from pykms_RequestV4 import kmsRequestV4
from pykms_RequestV5 import kmsRequestV5
from pykms_RequestV6 import kmsRequestV6
from pykms_RpcBase import rpcBase
from pykms_DB2Dict import kmsDB2Dict
from pykms_Misc import logger_create
from pykms_Format import justify, byterize, enco, deco, ShellMessage
clt_description = 'KMS Client Emulator written in Python'
clt_version = 'py-kms_2019-05-15'
clt_config = {}
#---------------------------------------------------------------------------------------------------------------------------------------------------------
loggerclt = logging.getLogger('logclt')
# 'help' string - 'default' value - 'dest' string.
clt_options = {
'ip' : {'help' : 'The IP address or hostname of the KMS server.', 'def' : "0.0.0.0", 'des' : "ip"},
'port' : {'help' : 'The port the KMS service is listening on. The default is \"1688\".', 'def' : 1688, 'des' : "port"},
'mode' : {'help' : 'Use this flag to manually specify a Microsoft product for testing the server. The default is \"Windows81\"',
'def' : "Windows8.1", 'des' : "mode",
'choi' : ["WindowsVista","Windows7","Windows8","Windows8.1","Windows10","Office2010","Office2013","Office2016","Office2019"]},
'cmid' : {'help' : 'Use this flag to manually specify a CMID to use. If no CMID is specified, a random CMID will be generated.',
'def' : None, 'des' : "cmid"},
'name' : {'help' : 'Use this flag to manually specify an ASCII machineName to use. If no machineName is specified a random machineName \
will be generated.', 'def' : None, 'des' : "machineName"},
'llevel' : {'help' : 'Use this option to set a log level. The default is \"ERROR\".', 'def' : "ERROR", 'des' : "loglevel",
'choi' : ["CRITICAL", "ERROR", "WARNING", "INFO", "DEBUG", "MINI"]},
'lfile' : {'help' : 'Use this option to set an output log file. The default is \"pykms_logclient.log\" or type \"STDOUT\" to view log info on stdout.',
'def' : os.path.dirname(os.path.abspath( __file__ )) + "/pykms_logclient.log", 'des' : "logfile"},
'lsize' : {'help' : 'Use this flag to set a maximum size (in MB) to the output log file. Desactivated by default.', 'def' : 0, 'des': "logsize"},
}
def client_options():
parser = argparse.ArgumentParser(description = clt_description, epilog = 'version: ' + clt_version)
parser.add_argument("ip", nargs = "?", action = "store", default = clt_options['ip']['def'], help = clt_options['ip']['help'], type = str)
parser.add_argument("port", nargs = "?", action = "store", default = clt_options['port']['def'], help = clt_options['port']['help'], type = int)
parser.add_argument("-m", "--mode", dest = clt_options['mode']['des'], default = clt_options['mode']['def'], choices = clt_options['mode']['choi'],
help = clt_options['mode']['help'], type = str)
parser.add_argument("-c", "--cmid", dest = clt_options['cmid']['des'], default = clt_options['cmid']['def'], help = clt_options['cmid']['help'], type = str)
parser.add_argument("-n", "--name", dest = clt_options['name']['des'] , default = clt_options['name']['def'], help = clt_options['name']['help'], type = str)
parser.add_argument("-V", "--loglevel", dest = clt_options['llevel']['des'], action = "store", choices = clt_options['llevel']['choi'],
default = clt_options['llevel']['def'], help = clt_options['llevel']['help'], type = str)
parser.add_argument("-F", "--logfile", dest = clt_options['lfile']['des'], action = "store", default = clt_options['lfile']['def'],
help = clt_options['lfile']['help'], type = str)
parser.add_argument("-S", "--logsize", dest = clt_options['lsize']['des'], action = "store", default = clt_options['lsize']['def'],
help = clt_options['lsize']['help'], type = float)
clt_config.update(vars(parser.parse_args()))
def client_check():
# Setup hidden or not messages.
ShellMessage.view = ( False if clt_config['logfile'] == 'STDOUT' else True )
# Create log.
logger_create(loggerclt, clt_config, mode = 'a')
# Check cmid.
if clt_config['cmid'] is not None:
try:
uuid.UUID(clt_config['cmid'])
except ValueError:
loggerclt.error("Bad CMID. Exiting...")
sys.exit()
# Check machineName.
if clt_config['machineName'] is not None:
if len(clt_config['machineName']) < 2 or len(clt_config['machineName']) > 63:
loggerclt.error("machineName must be between 2 and 63 characters in length.")
sys.exit()
clt_config['call_id'] = 1
def client_update():
kmsdb = kmsDB2Dict()
appitems = kmsdb[2]
for appitem in appitems:
kmsitems = appitem['KmsItems']
for kmsitem in kmsitems:
name = re.sub('\(.*\)', '', kmsitem['DisplayName']).replace('2015', '').replace(' ', '')
if name == clt_config['mode']:
skuitems = kmsitem['SkuItems']
# Select 'Enterprise' for Windows or 'Professional Plus' for Office.
for skuitem in skuitems:
if skuitem['DisplayName'].replace(' ','') == name + 'Enterprise' or \
skuitem['DisplayName'].replace(' ','') == name[:6] + 'ProfessionalPlus' + name[6:]:
clt_config['KMSClientSkuID'] = skuitem['Id']
clt_config['RequiredClientCount'] = int(kmsitem['NCountPolicy'])
clt_config['KMSProtocolMajorVersion'] = int(float(kmsitem['DefaultKmsProtocol']))
clt_config['KMSProtocolMinorVersion'] = 0
clt_config['KMSClientLicenseStatus'] = 2
clt_config['KMSClientAppID'] = appitem['Id']
clt_config['KMSClientKMSCountedID'] = kmsitem['Id']
break
def client_create():
loggerclt.info("\n\nConnecting to %s on port %d..." % (clt_config['ip'], clt_config['port']))
s = socket.create_connection((clt_config['ip'], clt_config['port']))
loggerclt.info("Connection successful !")
binder = pykms_RpcBind.handler(None, clt_config)
RPC_Bind = enco(str(binder.generateRequest()), 'latin-1')
loggerclt.info("Sending RPC bind request...")
ShellMessage.Process([-1, 1]).run()
s.send(RPC_Bind)
try:
ShellMessage.Process([-4, 7]).run()
bindResponse = s.recv(1024)
except socket.error as e:
if e.errno == errno.ECONNRESET:
loggerclt.error("Connection reset by peer. Exiting...")
sys.exit()
else:
raise
if bindResponse == '' or not bindResponse:
loggerclt.error("No data received ! Exiting...")
sys.exit()
packetType = MSRPCHeader(bindResponse)['type']
if packetType == rpcBase.packetType['bindAck']:
loggerclt.info("RPC bind acknowledged.")
ShellMessage.Process(8).run()
kmsRequest = createKmsRequest()
requester = pykms_RpcRequest.handler(kmsRequest, clt_config)
s.send(enco(str(requester.generateRequest()), 'latin-1'))
ShellMessage.Process([-1, 12]).run()
response = s.recv(1024)
loggerclt.debug("Response: \n%s\n" % justify(deco(binascii.b2a_hex(response), 'latin-1')))
ShellMessage.Process([-4, 20]).run()
parsed = MSRPCRespHeader(response)
kmsData = readKmsResponse(parsed['pduData'], kmsRequest, clt_config)
kmsResp = kmsData['response']
try:
hwid = kmsData['hwid']
loggerclt.info("KMS Host HWID: %s" % deco(binascii.b2a_hex(enco(hwid, 'latin-1')).upper(), 'utf-8'))
except KeyError:
pass
loggerclt.info("KMS Host ePID: %s" % kmsResp['kmsEpid'].encode('utf-8').decode('utf-16le'))
loggerclt.info("KMS Host Current Client Count: %s" % kmsResp['currentClientCount'])
loggerclt.info("KMS VL Activation Interval: %s" % kmsResp['vLActivationInterval'])
loggerclt.info("KMS VL Renewal Interval: %s" % kmsResp['vLRenewalInterval'])
loggerclt.mini("", extra = {'host': socket.gethostname() + " [" + clt_config["ip"] + "]",
'status' : "Activated",
'product' : clt_config["mode"]})
ShellMessage.Process(21).run()
elif packetType == rpcBase.packetType['bindNak']:
loggerclt.info(justify(MSRPCBindNak(bindResponse).dump(print_to_stdout = False)))
sys.exit()
else:
loggerclt.critical("Something went wrong.")
sys.exit()
def clt_main(with_gui = False):
if not with_gui:
# Parse options.
client_options()
# Check options.
client_check()
# Update Config.
client_update()
# Create and run client.
client_create()
def createKmsRequestBase():
requestDict = kmsBase.kmsRequestStruct()
requestDict['versionMinor'] = clt_config['KMSProtocolMinorVersion']
requestDict['versionMajor'] = clt_config['KMSProtocolMajorVersion']
requestDict['isClientVm'] = 0
requestDict['licenseStatus'] = clt_config['KMSClientLicenseStatus']
requestDict['graceTime'] = 43200
requestDict['applicationId'] = UUID(uuid.UUID(clt_config['KMSClientAppID']).bytes_le)
requestDict['skuId'] = UUID(uuid.UUID(clt_config['KMSClientSkuID']).bytes_le)
requestDict['kmsCountedId'] = UUID(uuid.UUID(clt_config['KMSClientKMSCountedID']).bytes_le)
requestDict['clientMachineId'] = UUID(uuid.UUID(clt_config['cmid']).bytes_le if (clt_config['cmid'] is not None) else uuid.uuid4().bytes_le)
requestDict['previousClientMachineId'] = '\0' * 16 # I'm pretty sure this is supposed to be a null UUID.
requestDict['requiredClientCount'] = clt_config['RequiredClientCount']
requestDict['requestTime'] = dt_to_filetime(datetime.datetime.utcnow())
requestDict['machineName'] = (clt_config['machineName'] if (clt_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
ShellMessage.Process(9).run()
requestDict = byterize(requestDict)
loggerclt.debug("Request Base Dictionary: \n%s\n" % justify(requestDict.dump(print_to_stdout = False)))
return requestDict
def createKmsRequest():
# Update the call ID
clt_config['call_id'] += 1
# KMS Protocol Major Version
if clt_config['KMSProtocolMajorVersion'] == 4:
handler = kmsRequestV4(None, clt_config)
elif clt_config['KMSProtocolMajorVersion'] == 5:
handler = kmsRequestV5(None, clt_config)
elif clt_config['KMSProtocolMajorVersion'] == 6:
handler = kmsRequestV6(None, clt_config)
else:
return None
requestBase = createKmsRequestBase()
return handler.generateRequest(requestBase)
def readKmsResponse(data, request, clt_config):
if clt_config['KMSProtocolMajorVersion'] == 4:
loggerclt.info("Received V4 response")
response = readKmsResponseV4(data, request)
elif clt_config['KMSProtocolMajorVersion'] == 5:
loggerclt.info("Received V5 response")
response = readKmsResponseV5(data)
elif clt_config['KMSProtocolMajorVersion'] == 6:
loggerclt.info("Received V6 response")
response = readKmsResponseV6(data)
else:
loggerclt.info("Unhandled response version: %d.%d" % (clt_config['KMSProtocolMajorVersion'], clt_config['KMSProtocolMinorVersion']))
loggerclt.info("I'm not even sure how this happened...")
return response
def readKmsResponseV4(data, request):
response = kmsRequestV4.ResponseV4(data)
hashed = kmsRequestV4(data, clt_config).generateHash(bytearray(enco(str(response['response']) , 'latin-1')))
if deco(hashed, 'latin-1') == response['hash']:
loggerclt.info("Response Hash has expected value !")
return response
def readKmsResponseV5(data):
response = kmsRequestV5.ResponseV5(data)
decrypted = kmsRequestV5(data, clt_config).decryptResponse(response)
return decrypted
def readKmsResponseV6(data):
response = kmsRequestV6.ResponseV5(data)
decrypted = kmsRequestV6(data, clt_config).decryptResponse(response)
message = decrypted['message']
return message
if __name__ == "__main__":
clt_main(with_gui = False)

47
py-kms/pykms_DB2Dict.py Normal file
View file

@ -0,0 +1,47 @@
#!/usr/bin/env python3
import os
import xml.etree.ElementTree as ET
#---------------------------------------------------------------------------------------------------------------------------------------------------------
def kmsDB2Dict():
path = os.path.join(os.path.dirname(__file__), 'KmsDataBase.xml')
root = ET.parse(path).getroot()
kmsdb, child1, child2, child3 = [ [] for _ in range(4) ]
## Get winbuilds.
for winbuild in root.iter('WinBuild'):
child1.append(winbuild.attrib)
kmsdb.append(child1)
## Get csvlkitem data.
child1 = []
for csvlk in root.iter('CsvlkItem'):
for activ in csvlk.iter('Activate'):
child2.append(activ.attrib['KmsItem'])
csvlk.attrib.update({'Activate' : child2})
child1.append(csvlk.attrib)
child2 = []
kmsdb.append(child1)
## Get appitem data.
child1 = []
for app in root.iter('AppItem'):
for kms in app.iter('KmsItem'):
for sku in kms.iter('SkuItem'):
child3.append(sku.attrib)
kms.attrib.update({'SkuItems' : child3})
child2.append(kms.attrib)
child3 = []
app.attrib.update({'KmsItems' : child2})
child1.append(app.attrib)
child2 = []
kmsdb.append(child1)
return kmsdb

731
py-kms/pykms_Dcerpc.py Normal file
View file

@ -0,0 +1,731 @@
#!/usr/bin/env python3
# SECUREAUTH LABS. Copyright 2018 SecureAuth Corporation. All rights reserved.
#
# 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/SecureAuthCorp/impacket/tree/master/tests/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/SecureAuthCorp/impacket/blob/master/impacket/dcerpc/v5/rpcrt.py
"""
from pykms_Structure import Structure
# 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
PFC_FIRST_FRAG = 0x01
PFC_LAST_FRAG = 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
PFC_RESERVED_1 = 0x08
PFC_CONC_MPX = 0x10
PFC_DID_NOT_EXECUTE = 0x20
PFC_MAYBE = 0x40
PFC_OBJECT_UUID = 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:
#https://docs.microsoft.com/windows/desktop/Rpc/rpc-return-values
#https://msdn.microsoft.com/library/default.asp?url=/library/en-us/randz/protocol/common_return_values.asp
#winerror.h
#https://www.opengroup.org/onlinepubs/9629399/apdxn.htm
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",
}
# 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'] = PFC_FIRST_FRAG | PFC_LAST_FRAG
self['type'] = MSRPC_REQUEST
self.__frag_len_set = 0
self['auth_len'] = 0
self['pduData'] = b''
self['auth_data'] = b''
self['sec_trailer'] = b''
self['pad'] = b''
def get_header_size(self):
return self._SIZE + (16 if (self["flags"] & PFC_OBJECT_UUID) > 0 else 0)
def get_packet(self):
if self['auth_data'] != b'':
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'] = b''
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'] = b''
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'] = b''
self['ctx_items'] = b''
self['sec_trailer'] = b''
self['auth_data'] = b''
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'] = b''

105
py-kms/pykms_Filetimes.py Normal file
View file

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

248
py-kms/pykms_Format.py Normal file
View file

@ -0,0 +1,248 @@
#!/usr/bin/env python3
from __future__ import print_function, unicode_literals
import re
import sys
import threading
try:
# Python 2.x imports
from StringIO import StringIO
import Queue as Queue
except ImportError:
# Python 3.x imports
from io import StringIO
import queue as Queue
pyver = sys.version_info[:2]
#----------------------------------------------------------------------------------------------------------------------------------------------------------
def enco(strg, typ = 'latin-1'):
if pyver >= (3, 0):
if isinstance(strg, str):
strgenc = strg.encode(typ)
return strgenc
else:
return strg
def deco(strg, typ = 'latin-1'):
if pyver >= (3, 0):
if isinstance(strg, bytes):
strgdec = strg.decode(typ)
return strgdec
else:
return strg
def byterize(obj):
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)
if pyver >= (3, 0):
objdict = obj.__dict__['fields']
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
##----------------------------------------------------------------------------------------------------------------------------------------------------
ColorMap = {'red' : '\x1b[91m',
'green' : '\x1b[92m',
'yellow' : '\x1b[93m',
'blue' : '\x1b[94m',
'magenta' : '\x1b[95m',
'cyan' : '\x1b[96m',
'white' : '\x1b[97m'
}
ExtraMap = {'end' : '\x1b[0m',
'bold' : '\x1b[1m',
'dim' : '\x1b[2m',
'italic' : '\x1b[3m',
'underlined' : '\x1b[4m',
'blink1' : '\x1b[5m',
'blink2' : '\x1b[6m',
'reverse' : '\x1b[7m',
'hidden' : '\x1b[8m',
'strike' : '\x1b[9m'
}
ColorExtraMap = dict(ColorMap, **ExtraMap)
MsgMap = {0 : {'text' : "{yellow}\n\t\t\tClient generating RPC Bind Request...{end}", 'where' : "clt"},
1 : {'text' : "{white}<==============={end}{yellow}\tClient sending RPC Bind Request...{end}", 'where' : "clt"},
2 : {'text' : "{yellow}Server received RPC Bind Request !!!\t\t\t\t{end}{white}<==============={end}", 'where' : "srv"},
3 : {'text' : "{yellow}Server parsing RPC Bind Request...{end}", 'where' : "srv"},
4 : {'text' : "{yellow}Server generating RPC Bind Response...{end}", 'where' : "srv"},
5 : {'text' : "{yellow}Server sending RPC Bind Response...\t\t\t\t{end}{white}===============>{end}", 'where' : "srv"},
6 : {'text' : "{green}{bold}RPC Bind acknowledged !!!\n\n{end}", 'where' : "srv"},
7 : {'text' : "{white}===============>{end}{yellow}\tClient received RPC Bind Response !!!{end}", 'where' : "clt"},
8 : {'text' : "{green}{bold}\t\t\tRPC Bind acknowledged !!!\n{end}", 'where' : "clt"},
9 : {'text' : "{blue}\t\t\tClient generating Activation Request dictionary...{end}", 'where' : "clt"},
10 : {'text' : "{blue}\t\t\tClient generating Activation Request data...{end}", 'where' : "clt"},
11 : {'text' : "{blue}\t\t\tClient generating RPC Activation Request...{end}", 'where' : "clt"},
12 : {'text' : "{white}<==============={end}{blue}\tClient sending RPC Activation Request...\n\n{end}", 'where' : "clt"},
13 : {'text' : "{blue}Server received RPC Activation Request !!!\t\t\t{end}{white}<==============={end}", 'where' : "srv"},
14 : {'text' : "{blue}Server parsing RPC Activation Request...{end}", 'where' : "srv"},
15 : {'text' : "{blue}Server processing KMS Activation Request...{end}", 'where' : "srv"},
16 : {'text' : "{blue}Server processing KMS Activation Response...{end}", 'where' : "srv"},
17 : {'text' : "{blue}Server generating RPC Activation Response...{end}", 'where' : "srv"},
18 : {'text' : "{blue}Server sending RPC Activation Response...\t\t\t{end}{white}===============>{end}", 'where' : "srv"},
19 : {'text' : "{green}{bold}Server responded, now in Stand by...\n{end}", 'where' : "srv"},
20 : {'text' : "{white}===============>{end}{blue}\tClient received Response !!!{end}", 'where' : "clt"},
21 : {'text' : "{green}{bold}\t\t\tActivation Done !!!{end}", 'where' : "clt"},
-1 : {'text' : "{white}Server receiving{end}", 'where' : "clt"},
-2 : {'text' : "{white}\n\n\t\t\t\t\t\t\t\tClient sending{end}", 'where' : "srv"},
-3 : {'text' : "{white}\t\t\t\t\t\t\t\tClient receiving{end}", 'where' : "srv"},
-4 : {'text' : "{white}\n\nServer sending{end}", 'where' : "clt"}
}
def pick_MsgMap(messagelist):
pattern = r"(?<!\{)\{([^}]+)\}(?!\})"
picktxt, pickarrw = [ [] for _ in range(2) ]
for messageitem in messagelist:
picklist = re.sub(pattern, '*', messageitem['text'])
picklist = list(filter(None, picklist.split('*')))
picktxt.append(picklist[0])
try:
pickarrw.append(picklist[1])
except IndexError:
pass
return picktxt, pickarrw
def unshell_MsgMap(arrows):
unMsgMap = {}
for key, values in MsgMap.items():
txt = pick_MsgMap([values])
if txt[0][0] in arrows:
unMsgMap.update({txt[1][0] : values['where']})
else:
unMsgMap.update({txt[0][0] : values['where']})
return unMsgMap
#-------------------------------------------------------------------------------------------------------------------------------------------------------
# https://stackoverflow.com/questions/230751/how-to-flush-output-of-print-function
if pyver < (3, 3):
old_print = print
def print(*args, **kwargs):
flush = kwargs.pop('flush', False)
old_print(*args, **kwargs)
if flush:
file = kwargs.get('file', sys.stdout)
file.flush() if file is not None else sys.stdout.flush()
# https://ryanjoneil.github.io/posts/2014-02-14-capturing-stdout-in-a-python-child-process.html
class ShellMessage(object):
view = None
class Collect(StringIO):
# Capture string sent to stdout.
def write(self, s):
StringIO.write(self, s)
class Process(object):
def __init__(self, nshell):
self.nshell = nshell
self.print_queue = Queue.Queue()
def run(self):
if not ShellMessage.view:
return
# Start thread process.
print_thread = threading.Thread(target = self.spawn(), args=(self.print_queue,))
print_thread.setDaemon(True)
print_thread.start()
# Do something with output.
toprint = self.read(0.1) # 0.1 s to let the shell output the result
# Redirect output.
from pykms_GuiBase import gui_redirect # Import after variables creation !
gui_redirect(toprint)
def spawn(self):
# Save everything that would otherwise go to stdout.
outstream = ShellMessage.Collect()
sys.stdout = outstream
try:
# Print something.
if isinstance(self.nshell, list):
for n in self.nshell:
print(MsgMap[n]['text'].format(**ColorExtraMap), flush = True)
else:
print(MsgMap[self.nshell]['text'].format(**ColorExtraMap), flush = True)
finally:
# Restore stdout and send content.
sys.stdout = sys.__stdout__
try:
self.print_queue.put(outstream.getvalue())
except Queue.Full:
pass
def read(self, timeout = None):
try:
toprint = self.print_queue.get(block = timeout is not None, timeout = timeout)
self.print_queue.task_done()
return toprint
except Queue.Empty:
return None
def unshell_message(ansi_string, m):
ansi_find = re.compile(r'\x1B\[[0-?]*[ -/]*[@-~]')
ansi_list = re.findall(ansi_find, ansi_string)
ansi_indx_start = [ n for n in range(len(ansi_string)) for ansi in list(set(ansi_list)) if ansi_string.find(ansi, n) == n ]
ansi_indx_stop = [ n + len(value) for n, value in zip(ansi_indx_start, ansi_list)]
ansi_indx = sorted(list(set(ansi_indx_start + ansi_indx_stop)))
msgcolored = {}
ColorMapReversed = dict(zip(ColorMap.values(), ColorMap.keys()))
ExtraMapReversed = dict(zip(ExtraMap.values(), ExtraMap.keys()))
for k in range(len(ansi_indx) - 1):
ansi_value = ansi_string[ansi_indx[k] : ansi_indx[k + 1]]
if ansi_value != '\x1b[0m':
tagname = "tag" + str(m).zfill(2)
if tagname not in msgcolored:
msgcolored[tagname] = {'color' : '', 'extra' : [], 'text' : ''}
if ansi_value in ColorMapReversed.keys():
msgcolored[tagname]['color'] = ColorMapReversed[ansi_value]
elif ansi_value in ExtraMapReversed.keys():
msgcolored[tagname]['extra'].append(ExtraMapReversed[ansi_value])
else:
msgcolored[tagname]['text'] = ansi_value
else:
m += 1
# Ordering.
msgcolored = dict(sorted(msgcolored.items()))
return msgcolored, m

464
py-kms/pykms_GuiBase.py Normal file
View file

@ -0,0 +1,464 @@
#!/usr/bin/env python3
import os
import sys
import threading
try:
# Python 2.x imports
import Tkinter as tk
import ttk
import tkMessageBox as messagebox
import tkFileDialog as filedialog
import tkFont
except ImportError:
# Python 3.x imports
import tkinter as tk
from tkinter import ttk
from tkinter import messagebox
from tkinter import filedialog
import tkinter.font as tkFont
from pykms_Server import srv_options, srv_version, srv_config, serverqueue, serverthread
from pykms_GuiMisc import ToolTip, TextDoubleScroll, TextRedirect, custom_background, make_clear
from pykms_Client import clt_options, clt_version, clt_config, clt_main
gui_description = 'py-kms GUI'
gui_version = 'v1.0'
##---------------------------------------------------------------------------------------------------------------------------------------------------------
def get_ip_address():
if os.name == 'posix':
try:
# Python 2.x import
import commands
except ImportError:
#Python 3.x import
import subprocess as commands
ip = commands.getoutput("hostname -I")
elif os.name == 'nt':
import socket
ip = socket.gethostbyname(socket.gethostname())
else:
ip = ''
print('Error: Couldn\'t get local ip')
return ip
def switch_dir(path):
if os.path.isdir(path):
os.chdir(path)
return True
if path == '':
os.chdir(os.getcwd())
return True
else:
return
def gui_redirect(str_to_print):
global txsrv, txclt, txcol, rclt
try:
TextRedirect.StdoutRedirect(txsrv, txclt, txcol, rclt, str_to_print)
except:
print(str_to_print)
##---------------------------------------------------------------------------------------------------------------------------------------------------------
class KmsGui(tk.Tk):
def browse(self, entrywidget, options):
path = filedialog.askdirectory()
if os.path.isdir(path):
entrywidget.delete('0', 'end')
entrywidget.insert('end', path + os.sep + os.path.basename(options['lfile']['def']))
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
self.wraplength = 200
## Define fonts and colors.
self.btnwinfont = tkFont.Font(family = 'Times', size = 12, weight = 'bold')
self.othfont = tkFont.Font(family = 'Times', size = 9, weight = 'bold')
self.optfont = tkFont.Font(family = 'Helvetica', size = 11, weight = 'bold')
self.msgfont = tkFont.Font(family = 'Helvetica', size = 7)
self.customcolors = { 'black' : '#000000',
'white' : '#FFFFFF',
'green' : '#90EE90',
'yellow' : '#FFFF00',
'magenta' : '#DA70D6',
'orange' : '#FFA500',
'red' : '#FF4500',
'blue' : '#1E90FF',
'cyan' : '#AFEEEE',
'lavender': '#E6E6FA',
}
self.gui_create()
def gui_create(self):
## Create server gui
self.gui_srv()
## Create client gui + other operations.
self.gui_complete()
## Create globals for printing process (redirect stdout).
global txsrv, txclt, txcol, rclt
txsrv = self.textboxsrv.get()
txclt = self.textboxclt.get()
txcol = self.customcolors
rclt = self.runbtnclt
## Redirect stderr.
sys.stderr = TextRedirect.StderrRedirect(txsrv, txclt, txcol)
def gui_srv(self):
## Create main containers. -------------------------------------------------------------------------------------------------------------
self.masterwin = tk.Canvas(self, borderwidth = 3, relief = tk.RIDGE)
self.btnsrvwin = tk.Canvas(self.masterwin, background = self.customcolors['white'], borderwidth = 3, relief = 'ridge')
self.optsrvwin = tk.Canvas(self.masterwin, background = self.customcolors['white'], borderwidth = 3, relief = 'ridge')
# self.optaddsrvwin = tk.Canvas(self.masterwin, background = self.customcolors['white'], borderwidth = 3, relief = 'ridge')
self.msgsrvwin = tk.Frame(self.masterwin, background = self.customcolors['black'], relief = 'ridge', width = 300, height = 200)
## Layout main containers.
self.masterwin.grid(row = 0, column = 0, sticky = 'nsew')
self.btnsrvwin.grid(row = 0, column = 1, padx = 2, pady = 2, sticky = 'nw')
self.optsrvwin.grid(row = 0, column = 2, padx = 2, pady = 2, sticky = 'nw')
# self.optaddsrvwin.grid(row = 0, column = 3, padx = 2, pady = 2, sticky = 'nw')
self.msgsrvwin.grid(row = 1, column = 2, padx = 1, pady = 1, sticky = 'nsew')
self.msgsrvwin.grid_propagate(False)
self.msgsrvwin.grid_columnconfigure(0, weight = 1)
self.msgsrvwin.grid_rowconfigure(0, weight = 1)
## Create widgets (btnsrvwin) -----------------------------------------------------------------------------------------------------------
self.statesrv = tk.Label(self.btnsrvwin, text = 'Server\nState:\nStopped', font = self.othfont, foreground = self.customcolors['red'])
self.runbtnsrv = tk.Button(self.btnsrvwin, text = 'START\nSERVER', background = self.customcolors['green'],
foreground = self.customcolors['white'], relief = 'flat', font = self.btnwinfont, command = self.srv_clickedmain)
self.shbtnclt = tk.Button(self.btnsrvwin, text = 'SHOW\nCLIENT', background = self.customcolors['magenta'],
foreground = self.customcolors['white'], relief = 'flat', font = self.btnwinfont, command = self.clt_showhide)
self.clearbtnsrv = tk.Button(self.btnsrvwin, text = 'CLEAR', background = self.customcolors['orange'],
foreground = self.customcolors['white'], relief = 'flat', font = self.btnwinfont,
command = lambda: make_clear([txsrv, txclt]))
self.exitbtnsrv = tk.Button(self.btnsrvwin, text = 'EXIT', background = self.customcolors['black'],
foreground = self.customcolors['white'], relief = 'flat', font = self.btnwinfont, command = self.destroy)
## Layout widgets (btnsrvwin)
self.statesrv.grid(row = 0, column = 0, padx = 2, pady = 2, sticky = 'ew')
self.runbtnsrv.grid(row = 1, column = 0, padx = 2, pady = 2, sticky = 'ew')
self.shbtnclt.grid(row = 2, column = 0, padx = 2, pady = 2, sticky = 'ew')
self.clearbtnsrv.grid(row = 3, column = 0, padx = 2, pady = 2, sticky = 'ew')
self.exitbtnsrv.grid(row = 4, column = 0, padx = 2, pady = 2, sticky = 'ew')
## Create widgets (optsrvwin) ------------------------------------------------------------------------------------------------------
# Version.
ver = tk.Label(self.optsrvwin, text = 'You are running server version: ' + srv_version, foreground = self.customcolors['red'],
font = self.othfont)
# Ip Address.
ipaddlbl = tk.Label(self.optsrvwin, text = 'IP Address: ', font = self.optfont)
self.ipadd = tk.Entry(self.optsrvwin, width = 10, font = self.optfont)
self.ipadd.insert('end', srv_options['ip']['def'])
ToolTip(self.ipadd, text = srv_options['ip']['help'], wraplength = self.wraplength)
myipadd = tk.Label(self.optsrvwin, text = 'Your IP address is: {}'.format(get_ip_address()), foreground = self.customcolors['red'],
font = self.othfont)
# Port.
portlbl = tk.Label(self.optsrvwin, text = 'Port: ', font = self.optfont)
self.port = tk.Entry(self.optsrvwin, width = 10, font = self.optfont)
self.port.insert('end', str(srv_options['port']['def']))
ToolTip(self.port, text = srv_options['port']['help'], wraplength = self.wraplength)
# EPID.
epidlbl = tk.Label(self.optsrvwin, text = 'EPID: ', font = self.optfont)
self.epid = tk.Entry(self.optsrvwin, width = 10, font = self.optfont)
self.epid.insert('end', str(srv_options['epid']['def']))
ToolTip(self.epid, text = srv_options['epid']['help'], wraplength = self.wraplength)
# LCID.
lcidlbl = tk.Label(self.optsrvwin, text = 'LCID: ', font = self.optfont)
self.lcid = tk.Entry(self.optsrvwin, width = 10, font = self.optfont)
self.lcid.insert('end', str(srv_options['lcid']['def']))
ToolTip(self.lcid, text = srv_options['lcid']['help'], wraplength = self.wraplength)
# HWID.
hwidlbl = tk.Label(self.optsrvwin, text = 'HWID: ', font = self.optfont)
self.hwid = tk.Entry(self.optsrvwin, width = 10, font = self.optfont)
self.hwid.insert('end', srv_options['hwid']['def'])
ToolTip(self.hwid, text = srv_options['hwid']['help'], wraplength = self.wraplength)
# Client Count
countlbl = tk.Label(self.optsrvwin, text = 'Client Count: ', font = self.optfont)
self.count = tk.Entry(self.optsrvwin, width = 10, font = self.optfont)
self.count.insert('end', str(srv_options['count']['def']))
ToolTip(self.count, text = srv_options['count']['help'], wraplength = self.wraplength)
# Activation Interval.
activlbl = tk.Label(self.optsrvwin, text = 'Activation Interval: ', font = self.optfont)
self.activ = tk.Entry(self.optsrvwin, width = 10, font = self.optfont)
self.activ.insert('end', str(srv_options['activation']['def']))
ToolTip(self.activ, text = srv_options['activation']['help'], wraplength = self.wraplength)
# Renewal Interval.
renewlbl = tk.Label(self.optsrvwin, text = 'Activation Interval: ', font = self.optfont)
self.renew = tk.Entry(self.optsrvwin, width = 10, font = self.optfont)
self.renew.insert('end', str(srv_options['renewal']['def']))
ToolTip(self.renew, text = srv_options['renewal']['help'], wraplength = self.wraplength)
# Logfile.
filelbl = tk.Label(self.optsrvwin, text = 'Logfile Path / Name: ', font = self.optfont)
self.file = tk.Entry(self.optsrvwin, width = 10, font = self.optfont)
self.file.insert('end', srv_options['lfile']['def'])
ToolTip(self.file, text = srv_options['lfile']['help'], wraplength = self.wraplength)
filebtnwin = tk.Button(self.optsrvwin, text = 'Browse', command = lambda: self.browse(self.file, srv_options))
# Loglevel.
levellbl = tk.Label(self.optsrvwin, text = 'Loglevel: ', font = self.optfont)
self.level = ttk.Combobox(self.optsrvwin, values = tuple(srv_options['llevel']['choi']), width = 10)
self.level.set(srv_options['llevel']['def'])
ToolTip(self.level, text = srv_options['llevel']['help'], wraplength = self.wraplength)
# Sqlite database.
self.chkval = tk.BooleanVar()
self.chkval.set(srv_options['sql']['def'])
chksql = tk.Checkbutton(self.optsrvwin, text = 'Create Sqlite\nDatabase', font = self.optfont, var = self.chkval)
ToolTip(chksql, text = srv_options['sql']['help'], wraplength = self.wraplength)
## Layout widgets (optsrvwin)
ver.grid(row = 0, column = 0, columnspan = 3, padx = 5, pady = 5, sticky = 'ew')
ipaddlbl.grid(row = 1, column = 0, padx = 5, pady = 5, sticky = 'e')
self.ipadd.grid(row = 1, column = 1, padx = 5, pady = 5, sticky = 'ew')
myipadd.grid(row = 2, column = 1, columnspan = 2, padx = 5, pady = 5, sticky = 'ew')
portlbl.grid(row = 3, column = 0, padx = 5, pady = 5, sticky = 'e')
self.port.grid(row = 3, column = 1, padx = 5, pady = 5, sticky = 'ew')
epidlbl.grid(row = 4, column = 0, padx = 5, pady = 5, sticky = 'e')
self.epid.grid(row = 4, column = 1, padx = 5, pady = 5, sticky = 'ew')
lcidlbl.grid(row = 5, column = 0, padx = 5, pady = 5, sticky = 'e')
self.lcid.grid(row = 5, column = 1, padx = 5, pady = 5, sticky = 'ew')
hwidlbl.grid(row = 6, column = 0, padx = 5, pady = 5, sticky = 'e')
self.hwid.grid(row = 6, column = 1, padx = 5, pady = 5, sticky = 'ew')
countlbl.grid(row = 7, column = 0, padx = 5, pady = 5, sticky = 'e')
self.count.grid(row = 7, column = 1, padx = 5, pady = 5, sticky = 'ew')
activlbl.grid(row = 8, column = 0, padx = 5, pady = 5, sticky = 'e')
self.activ.grid(row = 8, column = 1, padx = 5, pady = 5, sticky = 'ew')
renewlbl.grid(row = 9, column = 0, padx = 5, pady = 5, sticky = 'e')
self.renew.grid(row = 9, column = 1, padx = 5, pady = 5, sticky = 'ew')
filelbl.grid(row = 10, column = 0, padx = 5, pady = 5, sticky = 'e')
self.file.grid(row = 10, column = 1, padx = 5, pady = 5, sticky = 'ew')
filebtnwin.grid(row = 10, column = 2, padx = 5, pady = 5, sticky = 'ew')
levellbl.grid(row = 11, column = 0, padx = 5, pady = 5, sticky = 'e')
self.level.grid(row = 11, column = 1, padx = 5, pady = 5, sticky = 'ew')
chksql.grid(row = 12, column = 1, padx = 5, pady = 5, sticky = 'ew')
## Create widgets and layout (msgsrvwin) -----------------------------------------------------------------------------------------------
self.textboxsrv = TextDoubleScroll(self.msgsrvwin, background = self.customcolors['black'], wrap = 'word', state = 'disabled',
relief = 'ridge', font = self.msgfont)
self.textboxsrv.put()
## Create widgets (optaddsrvwin) -----------------------------------------------------------------------------------------------------
# self.timeout = tk.Entry(self.optaddsrvwin, width = 10)
# self.timeout.insert('end', '555')
## Layout widgets (optaddsrvwin)
# self.timeout.grid(row = 0, column = 0, padx = 5, pady = 5, sticky = 'e')
def gui_complete(self):
## Create client widgets (optcltwin, msgcltwin, btncltwin)
self.update_idletasks() # update Gui to get btnsrvwin values --> btncltwin.
self.iconify()
self.gui_clt()
minw, minh = self.winfo_width(), self.winfo_height()
# Main window custom background.
self.update_idletasks() # update Gui for custom background
self.iconify()
custom_background(self)
# Main window other modifications.
self.wm_attributes("-topmost", True)
self.protocol("WM_DELETE_WINDOW", lambda:0)
self.minsize(minw, minh)
self.resizable(True, False)
def get_position(self, genericwidget):
x, y = (genericwidget.winfo_x(), genericwidget.winfo_y())
w, h = (genericwidget.winfo_width(), genericwidget.winfo_height())
return x, y, w, h
def gui_clt(self):
self.optcltwin = tk.Canvas(self.masterwin, background = self.customcolors['white'], borderwidth = 3, relief = 'ridge')
self.msgcltwin = tk.Frame(self.masterwin, background = self.customcolors['black'], relief = 'ridge', width = 300, height = 200)
self.btncltwin = tk.Canvas(self.masterwin, background = self.customcolors['white'], borderwidth = 3, relief = 'ridge')
xb, yb, wb, hb = self.get_position(self.btnsrvwin)
self.btncltwin_X = xb + 2
self.btncltwin_Y = yb + hb + 10
self.btncltwin.place(x = self.btncltwin_X, y = self.btncltwin_Y, bordermode = 'inside', anchor = 'nw')
self.optcltwin.grid(row = 0, column = 4, padx = 2, pady = 2, sticky = 'nw')
self.msgcltwin.grid(row = 1, column = 4, padx = 1, pady = 1, sticky = 'nsew')
self.msgcltwin.grid_propagate(False)
self.msgcltwin.grid_columnconfigure(0, weight = 1)
self.msgcltwin.grid_rowconfigure(0, weight = 1)
# Create widgets (btncltwin) ------------------------------------------------------------------------------------------------------------
self.runbtnclt = tk.Button(self.btncltwin, text = 'START\nCLIENT', background = self.customcolors['blue'],
foreground = self.customcolors['white'], relief = 'flat', font = self.btnwinfont,
state = 'disabled', command = self.clt_clickedstart)
#self.othbutt = tk.Button(self.btncltwin, text = 'Botton\n2', background = self.customcolors['green'],
# foreground = self.customcolors['white'], relief = 'flat', font = self.btnwinfont)
# Layout widgets (btncltwin)
self.runbtnclt.grid(row = 0, column = 0, padx = 2, pady = 2, sticky = 'ew')
#self.othbutt.grid(row = 1, column = 0, padx = 2, pady = 2, sticky = 'ew')
# Create widgets (optcltwin) ------------------------------------------------------------------------------------------------------------
# Version.
cltver = tk.Label(self.optcltwin, text = 'You are running client version: ' + clt_version, foreground = self.customcolors['red'],
font = self.othfont)
# Ip Address.
cltipaddlbl = tk.Label(self.optcltwin, text = 'IP Address: ', font = self.optfont)
self.cltipadd = tk.Entry(self.optcltwin, width = 10, font = self.optfont)
self.cltipadd.insert('end', clt_options['ip']['def'])
ToolTip(self.cltipadd, text = clt_options['ip']['help'], wraplength = self.wraplength)
# Port.
cltportlbl = tk.Label(self.optcltwin, text = 'Port: ', font = self.optfont)
self.cltport = tk.Entry(self.optcltwin, width = 10, font = self.optfont)
self.cltport.insert('end', str(clt_options['port']['def']))
ToolTip(self.cltport, text = clt_options['port']['help'], wraplength = self.wraplength)
# Mode.
cltmodelbl = tk.Label(self.optcltwin, text = 'Mode: ', font = self.optfont)
self.cltmode = ttk.Combobox(self.optcltwin, values = tuple(clt_options['mode']['choi']), width = 10)
self.cltmode.set(clt_options['mode']['def'])
ToolTip(self.cltmode, text = clt_options['mode']['help'], wraplength = self.wraplength)
# CMID.
cltcmidlbl = tk.Label(self.optcltwin, text = 'CMID: ', font = self.optfont)
self.cltcmid = tk.Entry(self.optcltwin, width = 10, font = self.optfont)
self.cltcmid.insert('end', str(clt_options['cmid']['def']))
ToolTip(self.cltcmid, text = clt_options['cmid']['help'], wraplength = self.wraplength)
# Machine Name.
cltnamelbl = tk.Label(self.optcltwin, text = 'Machine Name: ', font = self.optfont)
self.cltname = tk.Entry(self.optcltwin, width = 10, font = self.optfont)
self.cltname.insert('end', str(clt_options['name']['def']))
ToolTip(self.cltname, text = clt_options['name']['help'], wraplength = self.wraplength)
# Logfile.
cltfilelbl = tk.Label(self.optcltwin, text = 'Logfile Path / Name: ', font = self.optfont)
self.cltfile = tk.Entry(self.optcltwin, width = 10, font = self.optfont)
self.cltfile.insert('end', clt_options['lfile']['def'])
ToolTip(self.cltfile, text = clt_options['lfile']['help'], wraplength = self.wraplength)
cltfilebtnwin = tk.Button(self.optcltwin, text = 'Browse', command = lambda: self.browse(self.cltfile, clt_options))
# Loglevel.
cltlevellbl = tk.Label(self.optcltwin, text = 'Loglevel: ', font = self.optfont)
self.cltlevel = ttk.Combobox(self.optcltwin, values = tuple(clt_options['llevel']['choi']), width = 10)
self.cltlevel.set(clt_options['llevel']['def'])
ToolTip(self.cltlevel, text = clt_options['llevel']['help'], wraplength = self.wraplength)
# Layout widgets (optcltwin)
cltver.grid(row = 0, column = 0, columnspan = 3, padx = 5, pady = 5, sticky = 'ew')
cltipaddlbl.grid(row = 1, column = 0, padx = 5, pady = 5, sticky = 'e')
self.cltipadd.grid(row = 1, column = 1, padx = 5, pady = 5, sticky = 'ew')
cltportlbl.grid(row = 2, column = 0, padx = 5, pady = 5, sticky = 'e')
self.cltport.grid(row = 2, column = 1, padx = 5, pady = 5, sticky = 'ew')
cltmodelbl.grid(row = 3, column = 0, padx = 5, pady = 5, sticky = 'e')
self.cltmode.grid(row = 3, column = 1, padx = 5, pady = 5, sticky = 'ew')
cltcmidlbl.grid(row = 4, column = 0, padx = 5, pady = 5, sticky = 'e')
self.cltcmid.grid(row = 4, column = 1, padx = 5, pady = 5, sticky = 'ew')
cltnamelbl.grid(row = 5, column = 0, padx = 5, pady = 5, sticky = 'e')
self.cltname.grid(row = 5, column = 1, padx = 5, pady = 5, sticky = 'ew')
cltfilelbl.grid(row = 6, column = 0, padx = 5, pady = 5, sticky = 'ew')
self.cltfile.grid(row = 6, column = 1, padx = 5, pady = 5, sticky = 'e')
cltfilebtnwin.grid(row = 6, column = 2, padx = 5, pady = 5, sticky = 'ew')
cltlevellbl.grid(row = 7, column = 0, padx = 5, pady = 5, sticky = 'e')
self.cltlevel.grid(row = 7, column = 1, padx = 5, pady = 5, sticky = 'ew')
# Create widgets and layout (msgcltwin) ----------------------------------------------------------------------------------------------------------
self.textboxclt = TextDoubleScroll(self.msgcltwin, background = self.customcolors['black'], wrap = 'word', state = 'disabled',
relief = 'ridge', font = self.msgfont)
self.textboxclt.put()
def proper_none(self, value):
value = None if value == 'None' else value
try:
return int(value)
except TypeError:
return value
def clt_showhide(self, force = False):
if self.optcltwin.winfo_ismapped() or force:
self.shbtnclt['text'] = 'SHOW\nCLIENT'
self.optcltwin.grid_remove()
self.msgcltwin.grid_remove()
self.btncltwin.place_forget()
else:
self.shbtnclt['text'] = 'HIDE\nCLIENT'
self.optcltwin.grid()
self.msgcltwin.grid()
self.btncltwin.place(x = self.btncltwin_X, y = self.btncltwin_Y, bordermode = 'inside', anchor = 'nw')
def srv_clickedmain(self):
if self.runbtnsrv['text'] == 'START\nSERVER':
if self.srv_clickedstart():
self.runbtnsrv.configure(text = 'STOP\nSERVER', background = self.customcolors['red'],
foreground = self.customcolors['white'])
self.runbtnclt.configure(state = 'normal')
elif self.runbtnsrv['text'] == 'STOP\nSERVER':
self.srv_clickedstop()
self.runbtnsrv.configure(text = 'START\nSERVER', background = self.customcolors['green'],
foreground = self.customcolors['white'])
self.runbtnclt.configure(state = 'disabled')
def srv_clickedstart(self):
ok = False
if switch_dir(os.path.dirname(self.file.get())):
if self.file.get().lower().endswith('.log'):
# Load dict.
srv_config[srv_options['ip']['des']] = self.ipadd.get()
srv_config[srv_options['port']['des']] = int(self.port.get())
srv_config[srv_options['epid']['des']] = self.proper_none(self.epid.get())
srv_config[srv_options['lcid']['des']] = int(self.lcid.get())
srv_config[srv_options['hwid']['des']] = self.hwid.get()
srv_config[srv_options['count']['des']] = self.proper_none(self.count.get())
srv_config[srv_options['activation']['des']] = int(self.activ.get())
srv_config[srv_options['renewal']['des']] = int(self.renew.get())
srv_config[srv_options['lfile']['des']] = self.file.get()
srv_config[srv_options['llevel']['des']] = self.level.get()
srv_config[srv_options['sql']['des']] = self.chkval.get()
## TODO.
srv_config[srv_options['lsize']['des']] = 0
srv_config[srv_options['time']['des']] = 30
serverqueue.put('start')
# wait for switch.
while not serverthread.is_running:
pass
self.srv_togglestate()
ok = True
else:
messagebox.showerror('Invalid extension', 'Not a .log file !')
else:
messagebox.showerror('Invalid path', 'Path you have provided not found !')
return ok
def srv_clickedstop(self):
if serverthread.is_running:
serverqueue.put('stop')
serverthread.server.shutdown()
# wait for switch.
while serverthread.is_running:
pass
self.srv_togglestate()
def srv_togglestate(self):
if serverthread.is_running:
txt, color = ('Server\nState:\nServing', self.customcolors['green'])
else:
txt, color = ('Server\nState:\nStopped', self.customcolors['red'])
self.statesrv.configure(text = txt, foreground = color)
def clt_clickedstart(self):
if switch_dir(os.path.dirname(self.cltfile.get())):
if self.cltfile.get().lower().endswith('.log'):
# Load dict.
clt_config[clt_options['ip']['des']] = self.cltipadd.get()
clt_config[clt_options['port']['des']] = int(self.cltport.get())
clt_config[clt_options['mode']['des']] = self.cltmode.get()
clt_config[clt_options['cmid']['des']] = self.proper_none(self.cltcmid.get())
clt_config[clt_options['name']['des']] = self.proper_none(self.cltname.get())
clt_config[clt_options['lfile']['des']] = self.cltfile.get()
clt_config[clt_options['llevel']['des']] = self.cltlevel.get()
## TODO
clt_config[clt_options['lsize']['des']] = 0
clientthread = threading.Thread(target = clt_main, args=(True,))
clientthread.setDaemon(True)
clientthread.start()
else:
messagebox.showerror('Invalid extension', 'Not a .log file !')
else:
messagebox.showerror('Invalid path', 'Path you have provided not found !')

334
py-kms/pykms_GuiMisc.py Normal file
View file

@ -0,0 +1,334 @@
#!/usr/bin/env python3
import os
import re
import sys
from collections import Counter
try:
# Python 2.x imports
import Tkinter as tk
import ttk
import tkFont
except ImportError:
# Python 3.x imports
import tkinter as tk
from tkinter import ttk
import tkinter.font as tkFont
from pykms_Format import unshell_message, MsgMap, pick_MsgMap, unshell_MsgMap
#---------------------------------------------------------------------------------------------------------------------------------------------------------
# https://stackoverflow.com/questions/3221956/how-do-i-display-tooltips-in-tkinter
class ToolTip(object):
""" Create a tooltip for a given widget """
def __init__(self, widget, bg = '#FFFFEA', pad = (5, 3, 5, 3), text = 'widget info', waittime = 400, wraplength = 250):
self.waittime = waittime # ms
self.wraplength = wraplength # pixels
self.widget = widget
self.text = text
self.widget.bind("<Enter>", self.onEnter)
self.widget.bind("<Leave>", self.onLeave)
self.widget.bind("<ButtonPress>", self.onLeave)
self.bg = bg
self.pad = pad
self.id = None
self.tw = None
def onEnter(self, event = None):
self.schedule()
def onLeave(self, event = None):
self.unschedule()
self.hide()
def schedule(self):
self.unschedule()
self.id = self.widget.after(self.waittime, self.show)
def unschedule(self):
id_ = self.id
self.id = None
if id_:
self.widget.after_cancel(id_)
def show(self):
def tip_pos_calculator(widget, label, tip_delta = (10, 5), pad = (5, 3, 5, 3)):
w = widget
s_width, s_height = w.winfo_screenwidth(), w.winfo_screenheight()
width, height = (pad[0] + label.winfo_reqwidth() + pad[2],
pad[1] + label.winfo_reqheight() + pad[3])
mouse_x, mouse_y = w.winfo_pointerxy()
x1, y1 = mouse_x + tip_delta[0], mouse_y + tip_delta[1]
x2, y2 = x1 + width, y1 + height
x_delta = x2 - s_width
if x_delta < 0:
x_delta = 0
y_delta = y2 - s_height
if y_delta < 0:
y_delta = 0
offscreen = (x_delta, y_delta) != (0, 0)
if offscreen:
if x_delta:
x1 = mouse_x - tip_delta[0] - width
if y_delta:
y1 = mouse_y - tip_delta[1] - height
offscreen_again = y1 < 0 # out on the top
if offscreen_again:
# No further checks will be done.
# TIP:
# A further mod might automagically augment the
# wraplength when the tooltip is too high to be
# kept inside the screen.
y1 = 0
return x1, y1
bg = self.bg
pad = self.pad
widget = self.widget
# creates a toplevel window
self.tw = tk.Toplevel(widget)
# leaves only the label and removes the app window
self.tw.wm_overrideredirect(True)
win = tk.Frame(self.tw, background = bg, borderwidth = 0)
label = ttk.Label(win, text = self.text, justify = tk.LEFT, background = bg, relief = tk.SOLID, borderwidth = 0,
wraplength = self.wraplength)
label.grid(padx = (pad[0], pad[2]), pady = (pad[1], pad[3]), sticky=tk.NSEW)
win.grid()
x, y = tip_pos_calculator(widget, label)
self.tw.wm_geometry("+%d+%d" % (x, y))
def hide(self):
tw = self.tw
if tw:
tw.destroy()
self.tw = None
##--------------------------------------------------------------------------------------------------------------------------------------------------------
# https://stackoverflow.com/questions/2914603/segmentation-fault-while-redirecting-sys-stdout-to-tkinter-text-widget
# https://stackoverflow.com/questions/7217715/threadsafe-printing-across-multiple-processes-python-2-x
# https://stackoverflow.com/questions/3029816/how-do-i-get-a-thread-safe-print-in-python-2-6
# https://stackoverflow.com/questions/20303291/issue-with-redirecting-stdout-to-tkinter-text-widget-with-threads
def make_clear(widgetlist):
for widget in widgetlist:
widget.configure(state = 'normal')
widget.delete('1.0', 'end')
widget.configure(state = 'disabled')
class TextRedirect(object):
class StdoutRedirect(object):
tag_num = 0
listwhere = []
arrows, clt_msg_nonewline = pick_MsgMap([MsgMap[1], MsgMap[7], MsgMap[12], MsgMap[20]])
srv_msg_nonewline, _ = pick_MsgMap([MsgMap[2], MsgMap[5], MsgMap[13], MsgMap[18]])
arrows = list(set(arrows))
lenarrow = len(arrows[0])
unMsgMap = unshell_MsgMap(arrows)
def __init__(self, srv_text_space, clt_text_space, customcolors, runclt, str_to_print):
self.srv_text_space = srv_text_space
self.clt_text_space = clt_text_space
self.customcolors = customcolors
self.runclt = runclt
self.runclt.configure(state = 'disabled')
self.str_to_print = str_to_print
self.textbox_do()
def textbox_finish(self, message):
if all(x == "srv" for x in TextRedirect.StdoutRedirect.listwhere):
terminator = pick_MsgMap([MsgMap[19]])[0]
else:
terminator = pick_MsgMap([MsgMap[21]])[0]
if message in terminator:
TextRedirect.StdoutRedirect.tag_num = 0
self.runclt.configure(state = 'normal')
def textbox_clear(self):
if TextRedirect.StdoutRedirect.tag_num == 0:
# Clear "srv" and "clt" textboxs.
make_clear([self.srv_text_space, self.clt_text_space])
def textbox_write(self, tag, message, color, extras):
widget = self.textbox_choose(message)
TextRedirect.StdoutRedirect.listwhere.append(self.where)
self.maxchar = widget['width']
self.textbox_color(tag, widget, color, self.customcolors['black'], extras)
widget.configure(state = 'normal')
widget.insert('end', self.textbox_format(message), tag)
widget.see('end')
widget.configure(state = 'disabled')
self.textbox_finish(message)
def textbox_choose(self, message):
if message not in self.arrows:
self.remind = message
self.where = self.unMsgMap[message]
if self.where == "srv":
return self.srv_text_space
elif self.where == "clt":
return self.clt_text_space
else:
if self.remind in self.srv_msg_nonewline:
self.where = "srv"
return self.srv_text_space
else:
self.where = "clt"
return self.clt_text_space
def textbox_color(self, tag, widget, forecolor = 'white', backcolor = 'black', extras = []):
xfont = tkFont.Font(font = widget['font'])
for extra in extras:
if extra == 'bold':
xfont.configure(weight = "bold")
elif extra == 'italic':
xfont.configure(slant = "italic")
elif extra == 'underlined':
xfont.text_font.configure(underline = True)
elif extra == 'strike':
xfont.configure(overstrike = True)
widget.tag_configure(tag, foreground = forecolor, background = backcolor, font = xfont)
def textbox_format(self, message):
lenfixed = self.maxchar - len(message.replace('\t', ''))
if self.where == "srv":
if message in self.srv_msg_nonewline:
lung = lenfixed - self.lenarrow + 4
else:
lung = lenfixed + self.lenarrow + 10
if not message.endswith('\n'):
message += '\n'
elif self.where == "clt":
if message in self.clt_msg_nonewline:
lung = lenfixed - self.lenarrow
if not message.endswith('\n'):
message += '\n'
else:
lung = lenfixed + 10
if not message.endswith('\n') and message not in self.arrows:
message += '\n'
count = Counter(message)
countab = (count['\t'] if count['\t'] != 0 else 1)
message = message.replace('\t' * countab, ' ' * lung)
return message
def textbox_do(self):
self.textbox_clear()
msgs, TextRedirect.StdoutRedirect.tag_num = unshell_message(self.str_to_print, TextRedirect.StdoutRedirect.tag_num)
for tag in msgs:
self.textbox_write(tag, msgs[tag]['text'], self.customcolors[msgs[tag]['color']], msgs[tag]['extra'])
class StderrRedirect(StdoutRedirect):
def __init__(self, srv_text_space, clt_text_space, customcolors):
self.srv_text_space = srv_text_space
self.clt_text_space = clt_text_space
self.customcolors = customcolors
self.tag_err = 'STDERR'
def write(self, string):
self.textbox_clear()
self.textbox_color(self.tag_err, self.srv_text_space, self.customcolors['red'], self.customcolors['black'])
self.srv_text_space.configure(state = 'normal')
self.srv_text_space.insert('end', string, self.tag_err)
self.srv_text_space.see('end')
self.srv_text_space.configure(state = 'disabled')
##-------------------------------------------------------------------------------------------------------------------------------------------------------
class TextDoubleScroll(tk.Frame):
def __init__(self, master, **kwargs):
""" Initialize.
- horizontal scrollbar
- vertical scrollbar
- text widget
"""
self.master = master
tk.Frame.__init__(self, master)
self.textbox = tk.Text(self.master, **kwargs)
self.sizegrip = ttk.Sizegrip(self.master)
self.hs = ttk.Scrollbar(self.master, orient = "horizontal", command = self.on_scrollbar_x)
self.vs = ttk.Scrollbar(self.master, orient = "vertical", command = self.on_scrollbar_y)
self.textbox.configure(yscrollcommand = self.on_textscroll, xscrollcommand = self.hs.set)
def on_scrollbar_x(self, *args):
""" Horizontally scrolls text widget. """
self.textbox.xview(*args)
def on_scrollbar_y(self, *args):
""" Vertically scrolls text widget. """
self.textbox.yview(*args)
def on_textscroll(self, *args):
""" Moves the scrollbar and scrolls text widget when the mousewheel is moved on a text widget. """
self.vs.set(*args)
self.on_scrollbar_y('moveto', args[0])
def put(self, **kwargs):
""" Grid the scrollbars and textbox correctly. """
self.textbox.grid(row = 0, column = 0, padx = 3, pady = 3, sticky = "nsew")
self.vs.grid(row = 0, column = 1, sticky = "ns")
self.hs.grid(row = 1, column = 0, sticky = "we")
self.sizegrip.grid(row = 1, column = 1, sticky = "news")
def get(self):
""" Return the "frame" useful to place inner controls. """
return self.textbox
##--------------------------------------------------------------------------------------------------------------------------------------------------
def custom_background(window):
allwidgets = window.grid_slaves(0,0)[0].grid_slaves() + window.grid_slaves(0,0)[0].place_slaves()
widgets = [ widget for widget in allwidgets if widget.winfo_class() == 'Canvas']
try:
from PIL import Image, ImageTk
# Open Image.
img = Image.open(os.path.dirname(os.path.abspath( __file__ )) + "/pykms_Keys.gif")
# Resize image.
img.resize((window.winfo_width(), window.winfo_height()), Image.ANTIALIAS)
# Put semi-transparent background chunks.
window.backcrops = []
for widget in widgets:
x, y, w, h = window.get_position(widget)
cropped = img.crop((x, y, x + w, y + h))
cropped.putalpha(24)
window.backcrops.append(ImageTk.PhotoImage(cropped))
# Not in same loop to prevent reference garbage.
for crop, widget in zip(window.backcrops, widgets):
widget.create_image(1, 1, image = crop, anchor = 'nw')
# Put semi-transparent background overall.
img.putalpha(96)
window.backimg = ImageTk.PhotoImage(img)
window.masterwin.create_image(1, 1, image = window.backimg, anchor = 'nw')
except ImportError:
for widget in widgets:
widget.configure(background = window.customcolors['lavender'])
# Hide client.
window.clt_showhide(force = True)
# Show Gui.
window.deiconify()
##---------------------------------------------------------------------------------------------------------------------------------------------------------

BIN
py-kms/pykms_Keys.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 524 KiB

473
py-kms/pykms_Misc.py Normal file
View file

@ -0,0 +1,473 @@
#!/usr/bin/env python3
import sys
import logging
from logging.handlers import RotatingFileHandler
#-----------------------------------------------------------------------------------------------------------------------------------------------------------
# https://stackoverflow.com/questions/2183233/how-to-add-a-custom-loglevel-to-pythons-logging-facility
# https://stackoverflow.com/questions/17558552/how-do-i-add-custom-field-to-python-log-format-string
# https://stackoverflow.com/questions/1343227/can-pythons-logging-format-be-modified-depending-on-the-message-log-level
# https://stackoverflow.com/questions/14844970/modifying-logging-message-format-based-on-message-logging-level-in-python3
def add_logging_level(levelName, levelNum, methodName = None):
""" Adds a new logging level to the `logging` module and the currently configured logging class.
`levelName` becomes an attribute of the `logging` module with the value `levelNum`.
`methodName` becomes a convenience method for both `logging` itself and the class returned by `logging.getLoggerClass()`
(usually just `logging.Logger`). If `methodName` is not specified, `levelName.lower()` is used.
To avoid accidental clobberings of existing attributes, this method will raise an `AttributeError` if the level name
is already an attribute of the `logging` module or if the method name is already present .
Example
-------
>>> add_logging_level('TRACE', logging.DEBUG - 5)
>>> logging.getLogger(__name__).setLevel("TRACE")
>>> logging.getLogger(__name__).trace('that worked')
>>> logging.trace('so did this')
>>> logging.TRACE
5
"""
if not methodName:
methodName = levelName.lower()
if hasattr(logging, levelName) or hasattr(logging, methodName) or hasattr(logging.getLoggerClass(), methodName):
return
def logForLevel(self, message, *args, **kwargs):
if self.isEnabledFor(levelNum):
self._log(levelNum, message, args, **kwargs)
def logToRoot(message, *args, **kwargs):
logging.log(levelNum, message, *args, **kwargs)
logging.addLevelName(levelNum, levelName)
setattr(logging, levelName, levelNum)
setattr(logging.getLoggerClass(), methodName, logForLevel)
setattr(logging, methodName, logToRoot)
class LevelFormatter(logging.Formatter):
dfmt = '%a, %d %b %Y %H:%M:%S'
default_fmt = logging.Formatter('[%(asctime)s] [%(levelname)8s] %(message)s', datefmt = dfmt)
def __init__(self, formats):
""" `formats` is a dict { loglevel : logformat } """
self.formatters = {}
for loglevel in formats:
self.formatters[loglevel] = logging.Formatter(formats[loglevel], datefmt = self.dfmt)
def format(self, record):
formatter = self.formatters.get(record.levelno, self.default_fmt)
return formatter.format(record)
def logger_create(log_obj, config, mode = 'a'):
# Create new level.
add_logging_level('MINI', logging.CRITICAL + 10)
# Configure visualization.
if config['logfile'] == 'STDOUT':
# Only STDOUT.
log_handler = logging.StreamHandler(sys.stdout)
elif config['logfile'] == 'FILE&STDOUT':
# logfile and STDOUT.
# Not implemented yet. (maybe useless ?)
pass
else:
# Only logfile.
log_handler = RotatingFileHandler(filename = config['logfile'], mode = mode, maxBytes = int(config['logsize'] * 1024 * 512),
backupCount = 1, encoding = None, delay = 0)
log_handler.setLevel(config['loglevel'])
# Configure formattation.
formatter = LevelFormatter({logging.MINI : '[%(asctime)s] [%(levelname)8s] %(host)s %(status)s %(product)s %(message)s'})
log_handler.setFormatter(formatter)
# Attach.
log_obj.setLevel(config['loglevel'])
log_obj.addHandler(log_handler)
# Valid language identifiers to be used in the EPID (see "kms.c" in vlmcsd)
ValidLcid = [1025, 1026, 1027, 1028, 1029,
1030, 1031, 1032, 1033, 1034, 1035, 1036, 1037, 1038, 1039,
1040, 1041, 1042, 1043, 1044, 1045, 1046, 1048, 1049,
1050, 1051, 1052, 1053, 1054, 1056, 1057, 1058, 1059,
1060, 1061, 1062, 1063, 1065, 1066, 1067, 1068, 1069,
1071, 1074, 1076, 1077, 1078, 1079,
1080, 1081, 1082, 1083, 1086, 1087, 1088, 1089,
1091, 1092, 1093, 1094, 1095, 1097, 1098, 1099,
1100, 1102, 1103, 1104, 1106, 1110, 1111, 1114, 1125, 1131, 1153,
2049, 2052, 2055, 2057, 2058, 2060, 2064, 2067, 2068, 2070, 2074, 2077, 2092, 2107, 2110, 2115, 2155,
3073, 3076, 3079, 3081, 3082, 3084, 3098, 3131, 3179,
4097, 4100, 4103, 4105, 4106, 4108, 4122, 4155,
5121, 5124, 5127, 5129, 5130, 5132, 5146, 5179,
6145, 6153, 6154, 6156, 6170, 6203,
7169, 7177, 7178, 7194, 7227,
8193, 8201, 8202, 8251,
9217, 9225, 9226, 9275,
10241, 10249, 10250, 11265, 11273, 11274, 12289, 12297, 12298,
13313, 13321, 13322, 14337, 14346, 15361, 15370, 16385, 16394, 17418, 18442, 19466, 20490]
# http://joshpoley.blogspot.com/2011/09/hresults-user-0x004.html (slerror.h)
ErrorCodes = {
'SL_E_SRV_INVALID_PUBLISH_LICENSE' : (0xC004B001, 'The activation server determined that the license is invalid.'),
'SL_E_SRV_INVALID_PRODUCT_KEY_LICENSE' : (0xC004B002, 'The activation server determined that the license is invalid.'),
'SL_E_SRV_INVALID_RIGHTS_ACCOUNT_LICENSE' : (0xC004B003, 'The activation server determined that the license is invalid.'),
'SL_E_SRV_INVALID_LICENSE_STRUCTURE' : (0xC004B004, 'The activation server determined that the license is invalid.'),
'SL_E_SRV_AUTHORIZATION_FAILED' : (0xC004B005, 'The activation server determined that the license is invalid.'),
'SL_E_SRV_INVALID_BINDING' : (0xC004B006, 'The activation server determined that the license is invalid.'),
'SL_E_SRV_SERVER_PONG' : (0xC004B007, 'The activation server reported that the computer could not connect to the activation server.'),
'SL_E_SRV_INVALID_PAYLOAD' : (0xC004B008, 'The activation server determined that the product could not be activated.'),
'SL_E_SRV_INVALID_SECURITY_PROCESSOR_LICENSE' : (0xC004B009, 'The activation server determined that the license is invalid.'),
'SL_E_SRV_BUSINESS_TOKEN_ENTRY_NOT_FOUND' : (0xC004B010, 'The activation server determined that required business token entry cannot be found.'),
'SL_E_SRV_CLIENT_CLOCK_OUT_OF_SYNC' : (0xC004B011, 'The activation server determined that your computer clock time is not correct. You must correct your clock before you can activate.'),
'SL_E_SRV_GENERAL_ERROR' : (0xC004B100, 'The activation server determined that the product could not be activated.'),
'SL_E_CHPA_PRODUCT_KEY_OUT_OF_RANGE' : (0xC004C001, 'The activation server determined the specified product key is invalid.'),
'SL_E_CHPA_INVALID_BINDING' : (0xC004C002, 'The activation server determined there is a problem with the specified product key.'),
'SL_E_CHPA_PRODUCT_KEY_BLOCKED' : (0xC004C003, 'The activation server determined the specified product key has been blocked.'),
'SL_E_CHPA_INVALID_PRODUCT_KEY' : (0xC004C004, 'The activation server determined the specified product key is invalid.'),
'SL_E_CHPA_BINDING_NOT_FOUND' : (0xC004C005, 'The activation server determined the license is invalid.'),
'SL_E_CHPA_BINDING_MAPPING_NOT_FOUND' : (0xC004C006, 'The activation server determined the license is invalid.'),
'SL_E_CHPA_UNSUPPORTED_PRODUCT_KEY' : (0xC004C007, 'The activation server determined the specified product key is invalid.'),
'SL_E_CHPA_MAXIMUM_UNLOCK_EXCEEDED' : (0xC004C008, 'The activation server reported that the product key has exceeded its unlock limit.'),
'SL_E_CHPA_ACTCONFIG_ID_NOT_FOUND' : (0xC004C009, 'The activation server determined the license is invalid.'),
'SL_E_CHPA_INVALID_PRODUCT_DATA_ID' : (0xC004C00A, 'The activation server determined the license is invalid.'),
'SL_E_CHPA_INVALID_PRODUCT_DATA' : (0xC004C00B, 'The activation server determined the license is invalid.'),
'SL_E_CHPA_SYSTEM_ERROR' : (0xC004C00C, 'The activation server experienced an error.'),
'SL_E_CHPA_INVALID_ACTCONFIG_ID' : (0xC004C00D, 'The activation server determined the product key is not valid.'),
'SL_E_CHPA_INVALID_PRODUCT_KEY_LENGTH' : (0xC004C00E, 'The activation server determined the specified product key is invalid.'),
'SL_E_CHPA_INVALID_PRODUCT_KEY_FORMAT' : (0xC004C00F, 'The activation server determined the specified product key is invalid.'),
'SL_E_CHPA_INVALID_PRODUCT_KEY_CHAR' : (0xC004C010, 'The activation server determined the specified product key is invalid.'),
'SL_E_CHPA_INVALID_BINDING_URI' : (0xC004C011, 'The activation server determined the license is invalid.'),
'SL_E_CHPA_NETWORK_ERROR' : (0xC004C012, 'The activation server experienced a network error.'),
'SL_E_CHPA_DATABASE_ERROR' : (0xC004C013, 'The activation server experienced an error.'),
'SL_E_CHPA_INVALID_ARGUMENT' : (0xC004C014, 'The activation server experienced an error.'),
'SL_E_CHPA_RESPONSE_NOT_AVAILABLE' : (0xC004C015, 'The activation server experienced an error.'),
'SL_E_CHPA_OEM_SLP_COA0' : (0xC004C016, 'The activation server reported that the specified product key cannot be used for online activation.'),
'SL_E_CHPA_PRODUCT_KEY_BLOCKED_IPLOCATION' : (0xC004C017, 'The activation server determined the specified product key has been blocked for this geographic location.'),
'SL_E_CHPA_DMAK_LIMIT_EXCEEDED' : (0xC004C020, 'The activation server reported that the Multiple Activation Key has exceeded its limit.'),
'SL_E_CHPA_DMAK_EXTENSION_LIMIT_EXCEEDED' : (0xC004C021, 'The activation server reported that the Multiple Activation Key extension limit has been exceeded.'),
'SL_E_CHPA_REISSUANCE_LIMIT_NOT_FOUND' : (0xC004C022, 'The activation server reported that the re-issuance limit was not found.'),
'SL_E_CHPA_OVERRIDE_REQUEST_NOT_FOUND' : (0xC004C023, 'The activation server reported that the override request was not found.'),
'SL_E_CHPA_TIMEBASED_ACTIVATION_BEFORE_START_DATE' : (0xC004C030, 'The activation server reported that time based activation attempted before start date.'),
'SL_E_CHPA_TIMEBASED_ACTIVATION_AFTER_END_DATE' : (0xC004C031, 'The activation server reported that time based activation attempted after end date.'),
'SL_E_CHPA_TIMEBASED_ACTIVATION_NOT_AVAILABLE' : (0xC004C032, 'The activation server reported that new time based activation is not available.'),
'SL_E_CHPA_TIMEBASED_PRODUCT_KEY_NOT_CONFIGURED' : (0xC004C033, 'The activation server reported that the time based product key is not configured for activation.'),
'SL_E_CHPA_NO_RULES_TO_ACTIVATE' : (0xC004C04F, 'The activation server reported that no business rules available to activate specified product key.'),
'SL_E_CHPA_GENERAL_ERROR' : (0xC004C050, 'The activation server experienced a general error.'),
'SL_E_CHPA_DIGITALMARKER_INVALID_BINDING' : (0xC004C051, 'The activation server determined the license is invalid.'),
'SL_E_CHPA_DIGITALMARKER_BINDING_NOT_CONFIGURED' : (0xC004C052, 'The activation server determined there is a problem with the specified product key.'),
'SL_E_CHPA_DYNAMICALLY_BLOCKED_PRODUCT_KEY' : (0xC004C060, 'The activation server determined the specified product key has been blocked.'),
'SL_E_INVALID_LICENSE_STATE_BREACH_GRACE' : (0xC004C291, 'Genuine Validation determined the license state is invalid.'),
'SL_E_INVALID_LICENSE_STATE_BREACH_GRACE_EXPIRED' : (0xC004C292, 'Genuine Validation determined the license state is invalid.'),
'SL_E_INVALID_TEMPLATE_ID' : (0xC004C2F6, 'Genuine Validation determined the validation input template identifier is invalid.'),
'SL_E_INVALID_XML_BLOB' : (0xC004C2FA, 'Genuine Validation determined the validation input data blob is invalid.'),
'SL_E_VALIDATION_BLOB_PARAM_NOT_FOUND' : (0xC004C327, 'Genuine Validation determined the validation input data blob parameter is invalid.'),
'SL_E_INVALID_CLIENT_TOKEN' : (0xC004C328, 'Genuine Validation determined the client token data is invalid.'),
'SL_E_INVALID_OFFLINE_BLOB' : (0xC004C329, 'Genuine Validation determined the offline data blob is invalid.'),
'SL_E_OFFLINE_VALIDATION_BLOB_PARAM_NOT_FOUND' : (0xC004C32A, 'Genuine Validation determined the offline data blob parameter is invalid.'),
'SL_E_INVALID_OSVERSION_TEMPLATEID' : (0xC004C32B, 'Genuine Validation determined the validation template identifier is invalid for this version of the Windows operating system.'),
'SL_E_OFFLINE_GENUINE_BLOB_REVOKED' : (0xC004C32C, 'Genuine Validation determined the offline genuine blob is revoked.'),
'SL_E_OFFLINE_GENUINE_BLOB_NOT_FOUND' : (0xC004C32D, 'Genuine Validation determined the offline genuine blob is not found.'),
'SL_E_CHPA_MSCH_RESPONSE_NOT_AVAILABLE_VGA' : (0xC004C3FF, 'The activation server determined the VGA service response is not available in the expected format.'),
'SL_E_INVALID_OS_FOR_PRODUCT_KEY' : (0xC004C401, 'Genuine Validation determined the product key is invalid for this version of the Windows operating system.'),
'SL_E_INVALID_FILE_HASH' : (0xC004C4A1, 'Genuine Validation determined the file hash is invalid.'),
'SL_E_VALIDATION_BLOCKED_PRODUCT_KEY' : (0xC004C4A2, 'Genuine Validation determined the product key has been blocked.'),
'SL_E_MISMATCHED_KEY_TYPES' : (0xC004C4A4, 'Genuine Validation determined the product key type is invalid.'),
'SL_E_VALIDATION_INVALID_PRODUCT_KEY' : (0xC004C4A5, 'Genuine Validation determined the product key is invalid.'),
'SL_E_INVALID_OEM_OR_VOLUME_BINDING_DATA' : (0xC004C4A7, 'Genuine Validation determined the OEM or Volume binding data is invalid.'),
'SL_E_INVALID_LICENSE_STATE' : (0xC004C4A8, 'Genuine Validation determined the license state is invalid.'),
'SL_E_IP_LOCATION_FALIED' : (0xC004C4A9, 'Genuine Validation determined the specified product key has been blocked for this geographic location.'),
'SL_E_SOFTMOD_EXPLOIT_DETECTED' : (0xC004C4AB, 'Genuine Validation detected Windows licensing exploits.'),
'SL_E_INVALID_TOKEN_DATA' : (0xC004C4AC, 'Genuine Validation determined the token activation data is invalid.'),
'SL_E_HEALTH_CHECK_FAILED_NEUTRAL_FILES' : (0xC004C4AD, 'Genuine Validation detected tampered Windows binaries.'),
'SL_E_HEALTH_CHECK_FAILED_MUI_FILES' : (0xC004C4AE, 'Genuine Validation detected tampered Windows binaries.'),
'SL_E_INVALID_AD_DATA' : (0xC004C4AF, 'Genuine Validation determined the active directory activation data is invalid.'),
'SL_E_INVALID_RSDP_COUNT' : (0xC004C4B0, 'Genuine Validation detected Windows licensing exploits.'),
'SL_E_ENGINE_DETECTED_EXPLOIT' : (0xC004C4B1, 'Genuine Validation detected Windows licensing exploits.'),
'SL_E_NOTIFICATION_BREACH_DETECTED' : (0xC004C531, 'Genuine Validation detected Windows licensing exploits.'),
'SL_E_NOTIFICATION_GRACE_EXPIRED' : (0xC004C532, 'Genuine Validation determined the license state is in notification due to expired grace.'),
'SL_E_NOTIFICATION_OTHER_REASONS' : (0xC004C533, 'Genuine Validation determined the license state is in notification.'),
'SL_E_NON_GENUINE_STATUS_LAST' : (0xC004C600, 'Genuine Validation determined your copy of Windows is not genuine.'),
'SL_E_CHPA_BUSINESS_RULE_INPUT_NOT_FOUND' : (0xC004C700, 'The activation server reported that business rule cound not find required input.'),
'SL_E_CHPA_NULL_VALUE_FOR_PROPERTY_NAME_OR_ID' : (0xC004C750, 'The activation server reported that NULL value specified for business property name and Id.'),
'SL_E_CHPA_UNKNOWN_PROPERTY_NAME' : (0xC004C751, 'The activation server reported that property name specifies unknown property.'),
'SL_E_CHPA_UNKNOWN_PROPERTY_ID' : (0xC004C752, 'The activation server reported that property Id specifies unknown property.'),
'SL_E_CHPA_FAILED_TO_UPDATE_PRODUCTKEY_BINDING' : (0xC004C755, 'The activation server reported that it failed to update product key binding.'),
'SL_E_CHPA_FAILED_TO_INSERT_PRODUCTKEY_BINDING' : (0xC004C756, 'The activation server reported that it failed to insert product key binding.'),
'SL_E_CHPA_FAILED_TO_DELETE_PRODUCTKEY_BINDING' : (0xC004C757, 'The activation server reported that it failed to delete product key binding.'),
'SL_E_CHPA_FAILED_TO_PROCESS_PRODUCT_KEY_BINDINGS_XML' : (0xC004C758, 'The activation server reported that it failed to process input XML for product key bindings.'),
'SL_E_CHPA_FAILED_TO_INSERT_PRODUCT_KEY_PROPERTY' : (0xC004C75A, 'The activation server reported that it failed to insert product key property.'),
'SL_E_CHPA_FAILED_TO_UPDATE_PRODUCT_KEY_PROPERTY' : (0xC004C75B, 'The activation server reported that it failed to update product key property.'),
'SL_E_CHPA_FAILED_TO_DELETE_PRODUCT_KEY_PROPERTY' : (0xC004C75C, 'The activation server reported that it failed to delete product key property.'),
'SL_E_CHPA_UNKNOWN_PRODUCT_KEY_TYPE' : (0xC004C764, 'The activation server reported that the product key type is unknown.'),
'SL_E_CHPA_PRODUCT_KEY_BEING_USED' : (0xC004C770, 'The activation server reported that the product key type is being used by another user.'),
'SL_E_CHPA_FAILED_TO_INSERT_PRODUCT_KEY_RECORD' : (0xC004C780, 'The activation server reported that it failed to insert product key record.'),
'SL_E_CHPA_FAILED_TO_UPDATE_PRODUCT_KEY_RECORD' : (0xC004C781, 'The activation server reported that it failed to update product key record.'),
'SL_REMAPPING_SP_PUB_API_INVALID_LICENSE' : (0xC004D000, ''),
'SL_REMAPPING_SP_PUB_API_INVALID_ALGORITHM_TYPE' : (0xC004D009, ''),
'SL_REMAPPING_SP_PUB_API_TOO_MANY_LOADED_ENVIRONMENTS' : (0xC004D00C, ''),
'SL_REMAPPING_SP_PUB_API_BAD_GET_INFO_QUERY' : (0xC004D012, ''),
'SL_REMAPPING_SP_PUB_API_INVALID_KEY_LENGTH' : (0xC004D055, ''),
'SL_REMAPPING_SP_PUB_API_NO_AES_PROVIDER' : (0xC004D073, ''),
'SL_REMAPPING_SP_PUB_API_HANDLE_NOT_COMMITED' : (0xC004D081, 'The handle was used before calling SPCommit with it.'),
'SL_REMAPPING_SP_PUB_GENERAL_NOT_INITIALIZED' : (0xC004D101, 'The security processor reported an initialization error.'),
'SL_REMAPPING_SP_STATUS_SYSTEM_TIME_SKEWED' : (0x8004D102, 'The security processor reported that the machine time is inconsistent with the trusted time.'),
'SL_REMAPPING_SP_STATUS_GENERIC_FAILURE' : (0xC004D103, 'The security processor reported that an error has occurred.'),
'SL_REMAPPING_SP_STATUS_INVALIDARG' : (0xC004D104, 'The security processor reported that invalid data was used.'),
'SL_REMAPPING_SP_STATUS_ALREADY_EXISTS' : (0xC004D105, 'The security processor reported that the value already exists.'),
'SL_REMAPPING_SP_STATUS_INSUFFICIENT_BUFFER' : (0xC004D107, 'The security processor reported that an insufficient buffer was used.'),
'SL_REMAPPING_SP_STATUS_INVALIDDATA' : (0xC004D108, 'The security processor reported that invalid data was used.'),
'SL_REMAPPING_SP_STATUS_INVALID_SPAPI_CALL' : (0xC004D109, 'The security processor reported that an invalid call was made.'),
'SL_REMAPPING_SP_STATUS_INVALID_SPAPI_VERSION' : (0xC004D10A, 'The security processor reported a version mismatch error.'),
'SL_REMAPPING_SP_STATUS_DEBUGGER_DETECTED' : (0x8004D10B, 'The security processor cannot operate while a debugger is attached.'),
'SL_REMAPPING_SP_STATUS_NO_MORE_DATA' : (0xC004D10C, 'No more data is available.'),
'SL_REMAPPING_SP_PUB_CRYPTO_INVALID_KEYLENGTH' : (0xC004D201, 'The length of the cryptopgraphic key material/blob is invalid.'),
'SL_REMAPPING_SP_PUB_CRYPTO_INVALID_BLOCKLENGTH' : (0xC004D202, 'The block length is not correct for this algorithm.'),
'SL_REMAPPING_SP_PUB_CRYPTO_INVALID_CIPHER' : (0xC004D203, 'The Cryptopgrahic cipher/algorithm type is invalid.'),
'SL_REMAPPING_SP_PUB_CRYPTO_INVALID_CIPHERMODE' : (0xC004D204, 'The specified cipher mode is invalid. For example both encrypt and decrypt cannot be specified for symmetric keys.'),
'SL_REMAPPING_SP_PUB_CRYPTO_UNKNOWN_PROVIDERID' : (0xC004D205, 'The SPAPIID for the specified Cryptographic Provider is unknown.'),
'SL_REMAPPING_SP_PUB_CRYPTO_UNKNOWN_KEYID' : (0xC004D206, 'The SPAPIID for the specified Cryptographic Key (type) is unknown.'),
'SL_REMAPPING_SP_PUB_CRYPTO_UNKNOWN_HASHID' : (0xC004D207, 'The SPAPIID for the specified Cryptographic Hash is unknown.'),
'SL_REMAPPING_SP_PUB_CRYPTO_UNKNOWN_ATTRIBUTEID' : (0xC004D208, 'The SPAPIID for the specified Cryptographic Attribute is unknown.'),
'SL_REMAPPING_SP_PUB_CRYPTO_HASH_FINALIZED' : (0xC004D209, 'The hash object has been finalized and can no longer be updated.'),
'SL_REMAPPING_SP_PUB_CRYPTO_KEY_NOT_AVAILABLE' : (0xC004D20A, 'The key is not available within the current state.'),
'SL_REMAPPING_SP_PUB_CRYPTO_KEY_NOT_FOUND' : (0xC004D20B, 'The key does not exist. It may not have have been created yet.'),
'SL_REMAPPING_SP_PUB_CRYPTO_NOT_BLOCK_ALIGNED' : (0xC004D20C, "The data length is not a multiple of the algorithm's block length."),
'SL_REMAPPING_SP_PUB_CRYPTO_INVALID_SIGNATURELENGTH' : (0xC004D20D, 'The length of the signature is not valid.'),
'SL_REMAPPING_SP_PUB_CRYPTO_INVALID_SIGNATURE' : (0xC004D20E, 'The signature does not correlate with the comparison hash.'),
'SL_REMAPPING_SP_PUB_CRYPTO_INVALID_BLOCK' : (0xC004D20F, 'The RSA block is not valid.'),
'SL_REMAPPING_SP_PUB_CRYPTO_INVALID_FORMAT' : (0xC004D210, 'The format of the RSA block is not valid.'),
'SL_REMAPPING_SP_PUB_CRYPTO_INVALID_PADDING' : (0xC004D211, 'The CBC padding is not valid.'),
'SL_REMAPPING_SP_PUB_TS_TAMPERED' : (0xC004D301, 'The security processor reported that the trusted data store was tampered.'),
'SL_REMAPPING_SP_PUB_TS_REARMED' : (0xC004D302, 'The security processor reported that the trusted data store was rearmed.'),
'SL_REMAPPING_SP_PUB_TS_RECREATED' : (0xC004D303, 'The security processor reported that the trusted store has been recreated.'),
'SL_REMAPPING_SP_PUB_TS_ENTRY_KEY_NOT_FOUND' : (0xC004D304, 'The security processor reported that entry key was not found in the trusted data store.'),
'SL_REMAPPING_SP_PUB_TS_ENTRY_KEY_ALREADY_EXISTS' : (0xC004D305, 'The security processor reported that the entry key already exists in the trusted data store.'),
'SL_REMAPPING_SP_PUB_TS_ENTRY_KEY_SIZE_TOO_BIG' : (0xC004D306, 'The security processor reported that the entry key is too big to fit in the trusted data store.'),
'SL_REMAPPING_SP_PUB_TS_MAX_REARM_REACHED' : (0xC004D307, 'The security processor reported that the maximum allowed number of re-arms has been exceeded. You must re-install the OS before trying to re-arm again.'),
'SL_REMAPPING_SP_PUB_TS_DATA_SIZE_TOO_BIG' : (0xC004D308, 'The security processor has reported that entry data size is too big to fit in the trusted data store.'),
'SL_REMAPPING_SP_PUB_TS_INVALID_HW_BINDING' : (0xC004D309, 'The security processor has reported that the machine has gone out of hardware tolerance.'),
'SL_REMAPPING_SP_PUB_TIMER_ALREADY_EXISTS' : (0xC004D30A, 'The security processor has reported that the secure timer already exists.'),
'SL_REMAPPING_SP_PUB_TIMER_NOT_FOUND' : (0xC004D30B, 'The security processor has reported that the secure timer was not found.'),
'SL_REMAPPING_SP_PUB_TIMER_EXPIRED' : (0xC004D30C, 'The security processor has reported that the secure timer has expired.'),
'SL_REMAPPING_SP_PUB_TIMER_NAME_SIZE_TOO_BIG' : (0xC004D30D, 'The security processor has reported that the secure timer name is too long.'),
'SL_REMAPPING_SP_PUB_TS_FULL' : (0xC004D30E, 'The security processor reported that the trusted data store is full.'),
'SL_REMAPPING_SP_PUB_TRUSTED_TIME_OK' : (0x4004D30F, 'Trusted time is already up-to-date.'),
'SL_REMAPPING_SP_PUB_TS_ENTRY_READ_ONLY' : (0xC004D310, 'Read-only entry cannot be modified.'),
'SL_REMAPPING_SP_PUB_TIMER_READ_ONLY' : (0xC004D311, 'Read-only timer cannot be modified.'),
'SL_REMAPPING_SP_PUB_TS_ATTRIBUTE_READ_ONLY' : (0xC004D312, 'Read-only attribute cannot be modified.'),
'SL_REMAPPING_SP_PUB_TS_ATTRIBUTE_NOT_FOUND' : (0xC004D313, 'Attribute not found.'),
'SL_REMAPPING_SP_PUB_TS_ACCESS_DENIED' : (0xC004D314, 'Trusted Store access denied.'),
'SL_REMAPPING_SP_PUB_TS_NAMESPACE_NOT_FOUND' : (0xC004D315, 'Namespace not found.'),
'SL_REMAPPING_SP_PUB_TS_NAMESPACE_IN_USE' : (0xC004D316, 'Namespace in use.'),
'SL_REMAPPING_SP_PUB_TS_TAMPERED_BREADCRUMB_LOAD_INVALID' : (0xC004D317, 'Trusted store tampered.'),
'SL_REMAPPING_SP_PUB_TS_TAMPERED_BREADCRUMB_GENERATION' : (0xC004D318, 'Trusted store tampered.'),
'SL_REMAPPING_SP_PUB_TS_TAMPERED_INVALID_DATA' : (0xC004D319, 'Trusted store tampered.'),
'SL_REMAPPING_SP_PUB_TS_TAMPERED_NO_DATA' : (0xC004D31A, 'Trusted store tampered.'),
'SL_REMAPPING_SP_PUB_TS_TAMPERED_DATA_BREADCRUMB_MISMATCH' : (0xC004D31B, 'Trusted store tampered'),
'SL_REMAPPING_SP_PUB_TS_TAMPERED_DATA_VERSION_MISMATCH' : (0xC004D31C, 'Trusted store tampered.'),
'SL_REMAPPING_SP_PUB_TAMPER_MODULE_AUTHENTICATION' : (0xC004D401, 'The security processor reported a system file mismatch error.'),
'SL_REMAPPING_SP_PUB_TAMPER_SECURITY_PROCESSOR_PATCHED' : (0xC004D402, 'The security processor reported a system file mismatch error.'),
'SL_REMAPPING_SP_PUB_KM_CACHE_TAMPER' : (0xC004D501, 'The security processor reported an error with the kernel data.'),
'SL_REMAPPING_SP_PUB_KM_CACHE_TAMPER_RESTORE_FAILED' : (0xC004D502, 'Kernel Mode Cache is tampered and the restore attempt failed.'),
'SL_REMAPPING_SP_PUB_KM_CACHE_IDENTICAL' : (0x4004D601, 'Kernel Mode Cache was not changed.'),
'SL_REMAPPING_SP_PUB_KM_CACHE_POLICY_CHANGED' : (0x4004D602, 'Reboot-requiring policies have changed.'),
'SL_REMAPPING_SP_STATUS_PUSHKEY_CONFLICT' : (0xC004D701, 'External decryption key was already set for specified feature.'),
'SL_REMAPPING_SP_PUB_PROXY_SOFT_TAMPER' : (0xC004D702, 'Error occured during proxy execution'),
'SL_E_INVALID_CONTEXT' : (0xC004E001, 'The Software Licensing Service determined that the specified context is invalid.'),
'SL_E_TOKEN_STORE_INVALID_STATE' : (0xC004E002, 'The Software Licensing Service reported that the license store contains inconsistent data.'),
'SL_E_EVALUATION_FAILED' : (0xC004E003, 'The Software Licensing Service reported that license evaluation failed.'),
'SL_E_NOT_EVALUATED' : (0xC004E004, 'The Software Licensing Service reported that the license has not been evaluated.'),
'SL_E_NOT_ACTIVATED' : (0xC004E005, 'The Software Licensing Service reported that the license is not activated.'),
'SL_E_INVALID_GUID' : (0xC004E006, 'The Software Licensing Service reported that the license contains invalid data.'),
'SL_E_TOKSTO_TOKEN_NOT_FOUND' : (0xC004E007, 'The Software Licensing Service reported that the license store does not contain the requested license.'),
'SL_E_TOKSTO_NO_PROPERTIES' : (0xC004E008, 'The Software Licensing Service reported that the license property is invalid.'),
'SL_E_TOKSTO_NOT_INITIALIZED' : (0xC004E009, 'The Software Licensing Service reported that the license store is not initialized.'),
'SL_E_TOKSTO_ALREADY_INITIALIZED' : (0xC004E00A, 'The Software Licensing Service reported that the license store is already initialized.'),
'SL_E_TOKSTO_NO_ID_SET' : (0xC004E00B, 'The Software Licensing Service reported that the license property is invalid.'),
'SL_E_TOKSTO_CANT_CREATE_FILE' : (0xC004E00C, 'The Software Licensing Service reported that the license could not be opened or created.'),
'SL_E_TOKSTO_CANT_WRITE_TO_FILE' : (0xC004E00D, 'The Software Licensing Service reported that the license could not be written.'),
'SL_E_TOKSTO_CANT_READ_FILE' : (0xC004E00E, 'The Software Licensing Service reported that the license store could not read the license file.'),
'SL_E_TOKSTO_CANT_PARSE_PROPERTIES' : (0xC004E00F, 'The Software Licensing Service reported that the license property is corrupted.'),
'SL_E_TOKSTO_PROPERTY_NOT_FOUND' : (0xC004E010, 'The Software Licensing Service reported that the license property is missing.'),
'SL_E_TOKSTO_INVALID_FILE' : (0xC004E011, 'The Software Licensing Service reported that the license store contains an invalid license file.'),
'SL_E_TOKSTO_CANT_CREATE_MUTEX' : (0xC004E012, 'The Software Licensing Service reported that the license store failed to start synchronization properly.'),
'SL_E_TOKSTO_CANT_ACQUIRE_MUTEX' : (0xC004E013, 'The Software Licensing Service reported that the license store failed to synchronize properly.'),
'SL_E_TOKSTO_NO_TOKEN_DATA' : (0xC004E014, 'The Software Licensing Service reported that the license property is invalid.'),
'SL_E_EUL_CONSUMPTION_FAILED' : (0xC004E015, 'The Software Licensing Service reported that license consumption failed.'),
'SL_E_PKEY_INVALID_CONFIG' : (0xC004E016, 'The Software Licensing Service reported that the product key is invalid.'),
'SL_E_PKEY_INVALID_UNIQUEID' : (0xC004E017, 'The Software Licensing Service reported that the product key is invalid.'),
'SL_E_PKEY_INVALID_ALGORITHM' : (0xC004E018, 'The Software Licensing Service reported that the product key is invalid.'),
'SL_E_PKEY_INTERNAL_ERROR' : (0xC004E019, 'The Software Licensing Service determined that validation of the specified product key failed.'),
'SL_E_LICENSE_INVALID_ADDON_INFO' : (0xC004E01A, 'The Software Licensing Service reported that invalid add-on information was found.'),
'SL_E_HWID_ERROR' : (0xC004E01B, 'The Software Licensing Service reported that not all hardware information could be collected.'),
'SL_E_PKEY_INVALID_KEYCHANGE1' : (0xC004E01C, 'This evaluation product key is no longer valid.'),
'SL_E_PKEY_INVALID_KEYCHANGE2' : (0xC004E01D, 'The new product key cannot be used on this installation of Windows. Type a different product key. (CD-AB)'),
'SL_E_PKEY_INVALID_KEYCHANGE3' : (0xC004E01E, 'The new product key cannot be used on this installation of Windows. Type a different product key. (AB-AB)'),
'SL_E_POLICY_OTHERINFO_MISMATCH' : (0xC004E020, 'The Software Licensing Service reported that there is a mismatched between a policy value and information stored in the OtherInfo section.'),
'SL_E_PRODUCT_UNIQUENESS_GROUP_ID_INVALID' : (0xC004E021, 'The Software Licensing Service reported that the Genuine information contained in the license is not consistent.'),
'SL_E_SECURE_STORE_ID_MISMATCH' : (0xC004E022, 'The Software Licensing Service reported that the secure store id value in license does not match with the current value.'),
'SL_E_INVALID_RULESET_RULE' : (0xC004E023, 'The Software Licensing Service reported that the notification rules appear to be invalid.'),
'SL_E_INVALID_CONTEXT_DATA' : (0xC004E024, 'The Software Licensing Service reported that the reported machine data appears to be invalid.'),
'SL_E_INVALID_HASH' : (0xC004E025, 'The Software Licensing Service reported that the data hash does not correspond to the data.'),
'SL_E_INVALID_USE_OF_ADD_ON_PKEY' : (0x8004E026, 'The Software Licensing Service reported that a valid product key for an add-on sku was entered where a Windows product key was expected.'),
'SL_E_WINDOWS_VERSION_MISMATCH' : (0xC004E027, 'The Software Licensing Service reported that the version of SPPSvc does not match the policy.'),
'SL_E_ACTIVATION_IN_PROGRESS' : (0xC004E028, 'The Software Licensing Service reported that there is another activation attempt in progress for this sku. Please wait for that attempt to complete before trying again.'),
'SL_E_STORE_UPGRADE_TOKEN_REQUIRED' : (0xC004E029, 'The Software Licensing Service reported that the activated license requires a corresponding Store upgrade license in order to work. Please visit the Store to purchase a new license or re-download an existing one.'),
'SL_E_STORE_UPGRADE_TOKEN_WRONG_EDITION' : (0xC004E02A, 'The Software Licensing Service reported that the Store upgrade license is not enabled for the current OS edition. Please visit the Store to purchase the appropriate license.'),
'SL_E_STORE_UPGRADE_TOKEN_WRONG_PID' : (0xC004E02B, 'The Software Licensing Service reported that the Store upgrade license does not match the current active product key. Please visit the Store to purchase a new license or re-download an existing one.'),
'SL_E_STORE_UPGRADE_TOKEN_NOT_PRS_SIGNED' : (0xC004E02C, 'The Software Licensing Service reported that the Store upgrade license does not match the current signing level for the installed Operating System. Please visit the Store to purchase a new license or re-download an existing one.'),
'SL_E_STORE_UPGRADE_TOKEN_WRONG_VERSION' : (0xC004E02D, 'The Software Licensing Service reported that the Store upgrade license does not enable the current version of the installed Operating System. Please visit the Store to purchase a new license or re-download an existing one.'),
'SL_E_STORE_UPGRADE_TOKEN_NOT_AUTHORIZED' : (0xC004E02E, 'The Software Licensing Service reported that the Store upgrade license could not be authorized. Please visit the Store to purchase a new license or re-download an existing one.'),
'SL_E_SFS_INVALID_FS_VERSION' : (0x8004E101, 'The Software Licensing Service reported that the Token Store file version is invalid.'),
'SL_E_SFS_INVALID_FD_TABLE' : (0x8004E102, 'The Software Licensing Service reported that the Token Store contains an invalid descriptor table.'),
'SL_E_SFS_INVALID_SYNC' : (0x8004E103, 'The Software Licensing Service reported that the Token Store contains a token with an invalid header/footer.'),
'SL_E_SFS_BAD_TOKEN_NAME' : (0x8004E104, 'The Software Licensing Service reported that a Token Store token has an invalid name.'),
'SL_E_SFS_BAD_TOKEN_EXT' : (0x8004E105, 'The Software Licensing Service reported that a Token Store token has an invalid extension.'),
'SL_E_SFS_DUPLICATE_TOKEN_NAME' : (0x8004E106, 'The Software Licensing Service reported that the Token Store contains a duplicate token.'),
'SL_E_SFS_TOKEN_SIZE_MISMATCH' : (0x8004E107, 'The Software Licensing Service reported that a token in the Token Store has a size mismatch.'),
'SL_E_SFS_INVALID_TOKEN_DATA_HASH' : (0x8004E108, 'The Software Licensing Service reported that a token in the Token Store contains an invalid hash.'),
'SL_E_SFS_FILE_READ_ERROR' : (0x8004E109, 'The Software Licensing Service reported that the Token Store was unable to read a token.'),
'SL_E_SFS_FILE_WRITE_ERROR' : (0x8004E10A, 'The Software Licensing Service reported that the Token Store was unable to write a token.'),
'SL_E_SFS_INVALID_FILE_POSITION' : (0x8004E10B, 'The Software Licensing Service reported that the Token Store attempted an invalid file operation.'),
'SL_E_SFS_NO_ACTIVE_TRANSACTION' : (0x8004E10C, 'The Software Licensing Service reported that there is no active transaction.'),
'SL_E_SFS_INVALID_FS_HEADER' : (0x8004E10D, 'The Software Licensing Service reported that the Token Store file header is invalid.'),
'SL_E_SFS_INVALID_TOKEN_DESCRIPTOR' : (0x8004E10E, 'The Software Licensing Service reported that a Token Store token descriptor is invalid.'),
'SL_E_INTERNAL_ERROR' : (0xC004F001, 'The Software Licensing Service reported an internal error.'),
'SL_E_RIGHT_NOT_CONSUMED' : (0xC004F002, 'The Software Licensing Service reported that rights consumption failed.'),
'SL_E_USE_LICENSE_NOT_INSTALLED' : (0xC004F003, 'The Software Licensing Service reported that the required license could not be found.'),
'SL_E_MISMATCHED_PKEY_RANGE' : (0xC004F004, 'The Software Licensing Service reported that the product key does not match the range defined in the license.'),
'SL_E_MISMATCHED_PID' : (0xC004F005, 'The Software Licensing Service reported that the product key does not match the product key for the license.'),
'SL_E_EXTERNAL_SIGNATURE_NOT_FOUND' : (0xC004F006, 'The Software Licensing Service reported that the signature file for the license is not available.'),
'SL_E_RAC_NOT_AVAILABLE' : (0xC004F007, 'The Software Licensing Service reported that the license could not be found.'),
'SL_E_SPC_NOT_AVAILABLE' : (0xC004F008, 'The Software Licensing Service reported that the license could not be found.'),
'SL_E_GRACE_TIME_EXPIRED' : (0xC004F009, 'The Software Licensing Service reported that the grace period expired.'),
'SL_E_MISMATCHED_APPID' : (0xC004F00A, 'The Software Licensing Service reported that the application ID does not match the application ID for the license.'),
'SL_E_NO_PID_CONFIG_DATA' : (0xC004F00B, 'The Software Licensing Service reported that the product identification data is not available.'),
'SL_I_OOB_GRACE_PERIOD' : (0x4004F00C, 'The Software Licensing Service reported that the application is running within the valid grace period.'),
'SL_I_OOT_GRACE_PERIOD' : (0x4004F00D, 'The Software Licensing Service reported that the application is running within the valid out of tolerance grace period.'),
'SL_E_MISMATCHED_SECURITY_PROCESSOR' : (0xC004F00E, 'The Software Licensing Service determined that the license could not be used by the current version of the security processor component.'),
'SL_E_OUT_OF_TOLERANCE' : (0xC004F00F, 'The Software Licensing Service reported that the hardware ID binding is beyond the level of tolerance.'),
'SL_E_INVALID_PKEY' : (0xC004F010, 'The Software Licensing Service reported that the product key is invalid.'),
'SL_E_LICENSE_FILE_NOT_INSTALLED' : (0xC004F011, 'The Software Licensing Service reported that the license file is not installed.'),
'SL_E_VALUE_NOT_FOUND' : (0xC004F012, 'The Software Licensing Service reported that the call has failed because the value for the input key was not found.'),
'SL_E_RIGHT_NOT_GRANTED' : (0xC004F013, 'The Software Licensing Service determined that there is no permission to run the software.'),
'SL_E_PKEY_NOT_INSTALLED' : (0xC004F014, 'The Software Licensing Service reported that the product key is not available.'),
'SL_E_PRODUCT_SKU_NOT_INSTALLED' : (0xC004F015, 'The Software Licensing Service reported that the license is not installed.'),
'SL_E_NOT_SUPPORTED' : (0xC004F016, 'The Software Licensing Service determined that the request is not supported.'),
'SL_E_PUBLISHING_LICENSE_NOT_INSTALLED' : (0xC004F017, 'The Software Licensing Service reported that the license is not installed.'),
'SL_E_LICENSE_SERVER_URL_NOT_FOUND' : (0xC004F018, 'The Software Licensing Service reported that the license does not contain valid location data for the activation server.'),
'SL_E_INVALID_EVENT_ID' : (0xC004F019, 'The Software Licensing Service determined that the requested event ID is invalid.'),
'SL_E_EVENT_NOT_REGISTERED' : (0xC004F01A, 'The Software Licensing Service determined that the requested event is not registered with the service.'),
'SL_E_EVENT_ALREADY_REGISTERED' : (0xC004F01B, 'The Software Licensing Service reported that the event ID is already registered.'),
'SL_E_DECRYPTION_LICENSES_NOT_AVAILABLE' : (0xC004F01C, 'The Software Licensing Service reported that the license is not installed.'),
'SL_E_LICENSE_SIGNATURE_VERIFICATION_FAILED' : (0xC004F01D, 'The Software Licensing Service reported that the verification of the license failed.'),
'SL_E_DATATYPE_MISMATCHED' : (0xC004F01E, 'The Software Licensing Service determined that the input data type does not match the data type in the license.'),
'SL_E_INVALID_LICENSE' : (0xC004F01F, 'The Software Licensing Service determined that the license is invalid.'),
'SL_E_INVALID_PACKAGE' : (0xC004F020, 'The Software Licensing Service determined that the license package is invalid.'),
'SL_E_VALIDITY_TIME_EXPIRED' : (0xC004F021, 'The Software Licensing Service reported that the validity period of the license has expired.'),
'SL_E_LICENSE_AUTHORIZATION_FAILED' : (0xC004F022, 'The Software Licensing Service reported that the license authorization failed.'),
'SL_E_LICENSE_DECRYPTION_FAILED' : (0xC004F023, 'The Software Licensing Service reported that the license is invalid.'),
'SL_E_WINDOWS_INVALID_LICENSE_STATE' : (0xC004F024, 'The Software Licensing Service reported that the license is invalid.'),
'SL_E_LUA_ACCESSDENIED' : (0xC004F025, 'The Software Licensing Service reported that the action requires administrator privilege.'),
'SL_E_PROXY_KEY_NOT_FOUND' : (0xC004F026, 'The Software Licensing Service reported that the required data is not found.'),
'SL_E_TAMPER_DETECTED' : (0xC004F027, 'The Software Licensing Service reported that the license is tampered.'),
'SL_E_POLICY_CACHE_INVALID' : (0xC004F028, 'The Software Licensing Service reported that the policy cache is invalid.'),
'SL_E_INVALID_RUNNING_MODE' : (0xC004F029, 'The Software Licensing Service cannot be started in the current OS mode.'),
'SL_E_SLP_NOT_SIGNED' : (0xC004F02A, 'The Software Licensing Service reported that the license is invalid.'),
'SL_E_CIDIID_INVALID_DATA' : (0xC004F02C, 'The Software Licensing Service reported that the format for the offline activation data is incorrect.'),
'SL_E_CIDIID_INVALID_VERSION' : (0xC004F02D, 'The Software Licensing Service determined that the version of the offline Confirmation ID (CID) is incorrect.'),
'SL_E_CIDIID_VERSION_NOT_SUPPORTED' : (0xC004F02E, 'The Software Licensing Service determined that the version of the offline Confirmation ID (CID) is not supported.'),
'SL_E_CIDIID_INVALID_DATA_LENGTH' : (0xC004F02F, 'The Software Licensing Service reported that the length of the offline Confirmation ID (CID) is incorrect.'),
'SL_E_CIDIID_NOT_DEPOSITED' : (0xC004F030, 'The Software Licensing Service determined that the Installation ID (IID) or the Confirmation ID (CID) could not been saved.'),
'SL_E_CIDIID_MISMATCHED' : (0xC004F031, 'The Installation ID (IID) and the Confirmation ID (CID) do not match. Please confirm the IID and reacquire a new CID if necessary.'),
'SL_E_INVALID_BINDING_BLOB' : (0xC004F032, 'The Software Licensing Service determined that the binding data is invalid.'),
'SL_E_PRODUCT_KEY_INSTALLATION_NOT_ALLOWED' : (0xC004F033, 'The Software Licensing Service reported that the product key is not allowed to be installed. Please see the eventlog for details.'),
'SL_E_EUL_NOT_AVAILABLE' : (0xC004F034, 'The Software Licensing Service reported that the license could not be found or was invalid.'),
'SL_E_VL_NOT_WINDOWS_SLP' : (0xC004F035, 'The Software Licensing Service reported that the computer could not be activated with a Volume license product key. Volume-licensed systems require upgrading from a qualifying operating system. Please contact your system administrator or use a different type of key.'),
'SL_E_VL_NOT_ENOUGH_COUNT' : (0xC004F038, 'The Software Licensing Service reported that the product could not be activated. The count reported by your Key Management Service (KMS) is insufficient. Please contact your system administrator.'),
'SL_E_VL_BINDING_SERVICE_NOT_ENABLED' : (0xC004F039, 'The Software Licensing Service reported that the product could not be activated. The Key Management Service (KMS) is not enabled.'),
'SL_E_VL_INFO_PRODUCT_USER_RIGHT' : (0x4004F040, 'The Software Licensing Service reported that the product was activated but the owner should verify the Product Use Rights.'),
'SL_E_VL_KEY_MANAGEMENT_SERVICE_NOT_ACTIVATED' : (0xC004F041, 'The Software Licensing Service determined that the Key Management Service (KMS) is not activated. KMS needs to be activated. Please contact system administrator.'),
'SL_E_VL_KEY_MANAGEMENT_SERVICE_ID_MISMATCH' : (0xC004F042, 'The Software Licensing Service determined that the specified Key Management Service (KMS) cannot be used.'),
'SL_E_PROXY_POLICY_NOT_UPDATED' : (0xC004F047, 'The Software Licensing Service reported that the proxy policy has not been updated.'),
'SL_E_CIDIID_INVALID_CHECK_DIGITS' : (0xC004F04D, 'The Software Licensing Service determined that the Installation ID (IID) or the Confirmation ID (CID) is invalid.'),
'SL_E_LICENSE_MANAGEMENT_DATA_NOT_FOUND' : (0xC004F04F, 'The Software Licensing Service reported that license management information was not found in the licenses.'),
'SL_E_INVALID_PRODUCT_KEY' : (0xC004F050, 'The Software Licensing Service reported that the product key is invalid.'),
'SL_E_BLOCKED_PRODUCT_KEY' : (0xC004F051, 'The Software Licensing Service reported that the product key is blocked.'),
'SL_E_DUPLICATE_POLICY' : (0xC004F052, 'The Software Licensing Service reported that the licenses contain duplicated properties.'),
'SL_E_MISSING_OVERRIDE_ONLY_ATTRIBUTE' : (0xC004F053, 'The Software Licensing Service determined that the license is invalid. The license contains an override policy that is not configured properly.'),
'SL_E_LICENSE_MANAGEMENT_DATA_DUPLICATED' : (0xC004F054, 'The Software Licensing Service reported that license management information has duplicated data.'),
'SL_E_BASE_SKU_NOT_AVAILABLE' : (0xC004F055, 'The Software Licensing Service reported that the base SKU is not available.'),
'SL_E_VL_MACHINE_NOT_BOUND' : (0xC004F056, 'The Software Licensing Service reported that the product could not be activated using the Key Management Service (KMS).'),
'SL_E_SLP_MISSING_ACPI_SLIC' : (0xC004F057, 'The Software Licensing Service reported that the computer BIOS is missing a required license.'),
'SL_E_SLP_MISSING_SLP_MARKER' : (0xC004F058, 'The Software Licensing Service reported that the computer BIOS is missing a required license.'),
'SL_E_SLP_BAD_FORMAT' : (0xC004F059, 'The Software Licensing Service reported that a license in the computer BIOS is invalid.'),
'SL_E_INVALID_PACKAGE_VERSION' : (0xC004F060, 'The Software Licensing Service determined that the version of the license package is invalid.'),
'SL_E_PKEY_INVALID_UPGRADE' : (0xC004F061, 'The Software Licensing Service determined that this specified product key can only be used for upgrading, not for clean installations.'),
'SL_E_ISSUANCE_LICENSE_NOT_INSTALLED' : (0xC004F062, 'The Software Licensing Service reported that a required license could not be found.'),
'SL_E_SLP_OEM_CERT_MISSING' : (0xC004F063, 'The Software Licensing Service reported that the computer is missing a required OEM license.'),
'SL_E_NONGENUINE_GRACE_TIME_EXPIRED' : (0xC004F064, 'The Software Licensing Service reported that the non-genuine grace period expired.'),
'SL_I_NONGENUINE_GRACE_PERIOD' : (0x4004F065, 'The Software Licensing Service reported that the application is running within the valid non-genuine grace period.'),
'SL_E_DEPENDENT_PROPERTY_NOT_SET' : (0xC004F066, 'The Software Licensing Service reported that the genuine information property can not be set before dependent property been set.'),
'SL_E_NONGENUINE_GRACE_TIME_EXPIRED_2' : (0xC004F067, 'The Software Licensing Service reported that the non-genuine grace period expired (type 2).'),
'SL_I_NONGENUINE_GRACE_PERIOD_2' : (0x4004F068, 'The Software Licensing Service reported that the application is running within the valid non-genuine grace period (type 2).'),
'SL_E_MISMATCHED_PRODUCT_SKU' : (0xC004F069, 'The Software Licensing Service reported that the product SKU is not found.'),
'SL_E_OPERATION_NOT_ALLOWED' : (0xC004F06A, 'The Software Licensing Service reported that the requested operation is not allowed.'),
'SL_E_VL_KEY_MANAGEMENT_SERVICE_VM_NOT_SUPPORTED' : (0xC004F06B, 'The Software Licensing Service determined that it is running in a virtual machine. The Key Management Service (KMS) is not supported in this mode.'),
'SL_E_VL_INVALID_TIMESTAMP' : (0xC004F06C, 'The Software Licensing Service reported that the product could not be activated. The Key Management Service (KMS) determined that the request timestamp is invalid.'),
'SL_E_PLUGIN_INVALID_MANIFEST' : (0xC004F071, 'The Software Licensing Service reported that the plug-in manifest file is incorrect.'),
'SL_E_APPLICATION_POLICIES_MISSING' : (0xC004F072, 'The Software Licensing Service reported that the license policies for fast query could not be found.'),
'SL_E_APPLICATION_POLICIES_NOT_LOADED' : (0xC004F073, 'The Software Licensing Service reported that the license policies for fast query have not been loaded.'),
'SL_E_VL_BINDING_SERVICE_UNAVAILABLE' : (0xC004F074, 'The Software Licensing Service reported that the product could not be activated. No Key Management Service (KMS) could be contacted. Please see the Application Event Log for additional information.'),
'SL_E_SERVICE_STOPPING' : (0xC004F075, 'The Software Licensing Service reported that the operation cannot be completed because the service is stopping.'),
'SL_E_PLUGIN_NOT_REGISTERED' : (0xC004F076, 'The Software Licensing Service reported that the requested plug-in cannot be found.'),
'SL_E_AUTHN_WRONG_VERSION' : (0xC004F077, 'The Software Licensing Service determined incompatible version of authentication data.'),
'SL_E_AUTHN_MISMATCHED_KEY' : (0xC004F078, 'The Software Licensing Service reported that the key is mismatched.'),
'SL_E_AUTHN_CHALLENGE_NOT_SET' : (0xC004F079, 'The Software Licensing Service reported that the authentication data is not set.'),
'SL_E_AUTHN_CANT_VERIFY' : (0xC004F07A, 'The Software Licensing Service reported that the verification could not be done.'),
'SL_E_SERVICE_RUNNING' : (0xC004F07B, 'The requested operation is unavailable while the Software Licensing Service is running.'),
'SL_E_SLP_INVALID_MARKER_VERSION' : (0xC004F07C, 'The Software Licensing Service determined that the version of the computer BIOS is invalid.'),
'SL_E_INVALID_PRODUCT_KEY_TYPE' : (0xC004F07D, 'The Software Licensing Service reported that the product key cannot be used for this type of activation.'),
'SL_E_CIDIID_MISMATCHED_PKEY' : (0xC004F07E, 'The Installation ID (IID) and the Confirmation ID (CID) do not match the product key.'),
'SL_E_CIDIID_NOT_BOUND' : (0xC004F07F, 'The Installation ID (IID) and the Confirmation ID (CID) are not bound to the current environment.'),
'SL_E_LICENSE_NOT_BOUND' : (0xC004F080, 'The Software Licensing Service reported that the license is not bound to the current environment.'),
'SL_E_VL_AD_AO_NOT_FOUND' : (0xC004F081, 'The Software Licensing Service reported that the Active Directory Activation Object could not be found or was invalid.'),
'SL_E_VL_AD_AO_NAME_TOO_LONG' : (0xC004F082, 'The Software Licensing Service reported that the name specified for the Active Directory Activation Object is too long.'),
'SL_E_VL_AD_SCHEMA_VERSION_NOT_SUPPORTED' : (0xC004F083, 'The Software Licensing Service reported that Active Directory-Based Activation is not supported in the current Active Directory schema.'),
'SL_E_NOT_GENUINE' : (0xC004F200, 'The Software Licensing Service reported that current state is not genuine.'),
'SL_E_EDITION_MISMATCHED' : (0xC004F210, 'The Software Licensing Service reported that the license edition does match the computer edition.'),
'SL_E_TKA_CHALLENGE_EXPIRED' : (0xC004F301, 'The Software Licensing Service reported that the product could not be activated. The token-based activation challenge has expired.'),
'SL_E_TKA_SILENT_ACTIVATION_FAILURE' : (0xC004F302, 'The Software Licensing Service reported that Silent Activation failed. The Software Licensing Service reported that there are no certificates found in the system that could activate the product without user interaction.'),
'SL_E_TKA_INVALID_CERT_CHAIN' : (0xC004F303, 'The Software Licensing Service reported that the certificate chain could not be built or failed validation.'),
'SL_E_TKA_GRANT_NOT_FOUND' : (0xC004F304, 'The Software Licensing Service reported that required license could not be found.'),
'SL_E_TKA_CERT_NOT_FOUND' : (0xC004F305, 'The Software Licensing Service reported that there are no certificates found in the system that could activate the product.'),
'SL_E_TKA_INVALID_SKU_ID' : (0xC004F306, 'The Software Licensing Service reported that this software edition does not support token-based activation.'),
'SL_E_TKA_INVALID_BLOB' : (0xC004F307, 'The Software Licensing Service reported that the product could not be activated. Activation data is invalid.'),
'SL_E_TKA_TAMPERED_CERT_CHAIN' : (0xC004F308, 'The Software Licensing Service reported that the product could not be activated. Activation data is tampered.'),
'SL_E_TKA_CHALLENGE_MISMATCH' : (0xC004F309, 'The Software Licensing Service reported that the product could not be activated. Activation challenge and response do not match.'),
'SL_E_TKA_INVALID_CERTIFICATE' : (0xC004F30A, 'The Software Licensing Service reported that the product could not be activated. The certificate does not match the conditions in the license.'),
'SL_E_TKA_INVALID_SMARTCARD' : (0xC004F30B, 'The Software Licensing Service reported that the inserted smartcard could not be used to activate the product.'),
'SL_E_TKA_FAILED_GRANT_PARSING' : (0xC004F30C, 'The Software Licensing Service reported that the token-based activation license content is invalid.'),
'SL_E_TKA_INVALID_THUMBPRINT' : (0xC004F30D, 'The Software Licensing Service reported that the product could not be activated. The thumbprint is invalid.'),
'SL_E_TKA_THUMBPRINT_CERT_NOT_FOUND' : (0xC004F30E, 'The Software Licensing Service reported that the product could not be activated. The thumbprint does not match any certificate.'),
'SL_E_TKA_CRITERIA_MISMATCH' : (0xC004F30F, 'The Software Licensing Service reported that the product could not be activated. The certificate does not match the criteria specified in the issuance license.'),
'SL_E_TKA_TPID_MISMATCH' : (0xC004F310, 'The Software Licensing Service reported that the product could not be activated. The certificate does not match the trust point identifier (TPID) specified in the issuance license.'),
'SL_E_TKA_SOFT_CERT_DISALLOWED' : (0xC004F311, 'The Software Licensing Service reported that the product could not be activated. A soft token cannot be used for activation.'),
'SL_E_TKA_SOFT_CERT_INVALID' : (0xC004F312, 'The Software Licensing Service reported that the product could not be activated. The certificate cannot be used because its private key is exportable.'),
'SL_E_TKA_CERT_CNG_NOT_AVAILABLE' : (0xC004F313, 'The Software Licensing Service reported that the CNG encryption library could not be loaded. The current certificate may not be available on this version of Windows.'),
'E_RM_UNKNOWN_ERROR' : (0xC004FC03, 'A networking problem has occurred while activating your copy of Windows.'),
'SL_I_TIMEBASED_VALIDITY_PERIOD' : (0x4004FC04, 'The Software Licensing Service reported that the application is running within the timebased validity period.'),
'SL_I_PERPETUAL_OOB_GRACE_PERIOD' : (0x4004FC05, 'The Software Licensing Service reported that the application has a perpetual grace period.'),
'SL_I_TIMEBASED_EXTENDED_GRACE_PERIOD' : (0x4004FC06, 'The Software Licensing Service reported that the application is running within the valid extended grace period.'),
'SL_E_VALIDITY_PERIOD_EXPIRED' : (0xC004FC07, 'The Software Licensing Service reported that the validity period expired.'),
'SL_E_IA_THROTTLE_LIMIT_EXCEEDED' : (0xC004FD00, "You've reached the request limit for automatic virtual machine activation. Try again later."),
'SL_E_IA_INVALID_VIRTUALIZATION_PLATFORM' : (0xC004FD01, "Windows isn't running on a supported Microsoft Hyper-V virtualization platform."),
'SL_E_IA_PARENT_PARTITION_NOT_ACTIVATED' : (0xC004FD02, "Windows isn't activated on the host machine. Please contact your system administrator."),
'SL_E_IA_ID_MISMATCH' : (0xC004FD03, "The host machine can't activate the edition of Windows on the virtual machine."),
'SL_E_IA_MACHINE_NOT_BOUND' : (0xC004FD04, "Windows isn't activated."),
'SL_E_TAMPER_RECOVERY_REQUIRES_ACTIVATION' : (0xC004FE00, 'The Software Licensing Service reported that activation is required to recover from tampering of SL Service trusted store.'),
}

View file

@ -0,0 +1,85 @@
#!/usr/bin/env python3
import datetime
import random
import time
import uuid
from ast import literal_eval
from pykms_DB2Dict import kmsDB2Dict
#---------------------------------------------------------------------------------------------------------------------------------------------------------
def epidGenerator(kmsId, version, lcid):
kmsdb = kmsDB2Dict()
winbuilds, csvlkitems, appitems = kmsdb[0], kmsdb[1], kmsdb[2]
hosts, pkeys = [ [] for _ in range(2) ]
# Product Specific Detection (Get all CSVLK GroupID and PIDRange good for EPID generation), then
# Generate Part 2: Group ID and Product Key ID Range
for csvlkitem in csvlkitems:
try:
if kmsId in [ uuid.UUID(kmsitem) for kmsitem in csvlkitem['Activate'] ]:
pkeys.append( (csvlkitem['GroupId'], csvlkitem['MinKeyId'], csvlkitem['MaxKeyId'], csvlkitem['InvalidWinBuild']) )
else:
# fallback to Windows Server 2019 parameters.
pkeys.append( ('206', '551000000', '570999999', '[0,1,2]') )
except IndexError:
# fallback to Windows Server 2019 parameters.
pkeys.append( ('206', '551000000', '570999999', '[0,1,2]') )
pkey = random.choice(pkeys)
GroupId, MinKeyId, MaxKeyId, Invalid = int(pkey[0]), int(pkey[1]), int(pkey[2]), literal_eval(pkey[3])
# Get all KMS Server Host Builds good for EPID generation, then
# Generate Part 1 & 7: Host Type and KMS Server OS Build
for winbuild in winbuilds:
try:
# Check versus "InvalidWinBuild".
if int(winbuild['WinBuildIndex']) not in Invalid:
hosts.append(winbuild)
except KeyError:
# fallback to Windows Server 2019 parameters.
hosts.append( {'BuildNumber':'17763', 'PlatformId':'3612', 'MinDate':'02/10/2018'} )
host = random.choice(hosts)
BuildNumber, PlatformId, MinDate = host['BuildNumber'], host['PlatformId'], host['MinDate']
# Generate Part 3 and Part 4: Product Key ID
productKeyID = random.randint(MinKeyId, MaxKeyId)
# 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
d = datetime.datetime.strptime(MinDate, "%d/%m/%Y")
minTime = datetime.date(d.year, d.month, d.day)
# 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(PlatformId).rjust(5, "0"))
result.append("-")
result.append(str(GroupId).rjust(5, "0"))
result.append("-")
result.append(str(productKeyID // 1000000).rjust(3, "0"))
result.append("-")
result.append(str(productKeyID % 1000000).rjust(6, "0"))
result.append("-")
result.append(str(licenseChannel).rjust(2, "0"))
result.append("-")
result.append(str(languageCode))
result.append("-")
result.append(str(BuildNumber).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,16 @@
#!/usr/bin/env python3
import struct
from pykms_Base import kmsBase
from pykms_Misc import ErrorCodes
#---------------------------------------------------------------------------------------------------------------------------------------------------------
class kmsRequestUnknown(kmsBase):
def executeRequestLogic(self):
finalResponse = bytearray()
finalResponse.extend(bytearray(struct.pack('<I', 0)))
finalResponse.extend(bytearray(struct.pack('<I', 0)))
finalResponse.extend(bytearray(struct.pack('<I', ErrorCodes['SL_E_VL_KEY_MANAGEMENT_SERVICE_ID_MISMATCH'][0])))
return finalResponse.decode('utf-8').encode('utf-8')

132
py-kms/pykms_RequestV4.py Normal file
View file

@ -0,0 +1,132 @@
#!/usr/bin/env python3
import binascii
import time
import logging
from pykms_Base import kmsBase
from pykms_Structure import Structure
from pykms_Aes import AES
from pykms_Format import justify, byterize, enco, deco, ShellMessage
#---------------------------------------------------------------------------------------------------------------------------------------------------------
loggersrv = logging.getLogger('logsrv')
# 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'),
('unknown', '!I=0x00000200'),
('bodyLength2', '<I'),
('response', ':', kmsBase.kmsResponseStruct),
('hash', '16s'),
('padding', ':'),
)
def executeRequestLogic(self):
requestData = self.RequestV4(self.data)
response = self.serverLogic(requestData['request'])
thehash = self.generateHash(bytearray(enco(str(response), 'latin-1')))
responseData = self.generateResponse(response, thehash)
time.sleep(1) # request sent back too quick for Windows 2008 R2, slow it down.
return responseData
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 bytes(hashBuffer)
def generateResponse(self, responseBuffer, thehash):
response = self.ResponseV4()
bodyLength = len(responseBuffer) + len(thehash)
response['bodyLength1'] = bodyLength
response['bodyLength2'] = bodyLength
response['response'] = responseBuffer
response['hash'] = thehash
response['padding'] = bytes(bytearray(self.getPadding(bodyLength)))
## Debug stuff.
ShellMessage.Process(16).run()
response = byterize(response)
loggersrv.debug("KMS V4 Response: \n%s\n" % justify(response.dump(print_to_stdout = False)))
loggersrv.debug("KMS V4 Response Bytes: \n%s\n" % justify(deco(binascii.b2a_hex(enco(str(response), 'latin-1')), 'utf-8')))
return str(response)
def generateRequest(self, requestBase):
thehash = self.generateHash(bytearray(enco(str(requestBase), 'latin-1')))
request = kmsRequestV4.RequestV4()
bodyLength = len(requestBase) + len(thehash)
request['bodyLength1'] = bodyLength
request['bodyLength2'] = bodyLength
request['request'] = requestBase
request['hash'] = thehash
request['padding'] = bytes(bytearray(self.getPadding(bodyLength)))
## Debug stuff.
ShellMessage.Process(10).run()
request = byterize(request)
loggersrv.debug("Request V4 Data: \n%s\n" % justify(request.dump(print_to_stdout = False)))
loggersrv.debug("Request V4: \n%s\n" % justify(deco(binascii.b2a_hex(enco(str(request), 'latin-1')), 'utf-8')))
return request

180
py-kms/pykms_RequestV5.py Normal file
View file

@ -0,0 +1,180 @@
#!/usr/bin/env python3
import logging
import binascii
import hashlib
import random
import pykms_Aes as aes
from pykms_Base import kmsBase
from pykms_Structure import Structure
from pykms_Format import justify, byterize, enco, deco, ShellMessage
#--------------------------------------------------------------------------------------------------------------------------------------------------------
loggersrv = logging.getLogger('logsrv')
class kmsRequestV5(kmsBase):
class RequestV5(Structure):
class Message(Structure):
commonHdr = ()
structure = (
('salt', '16s'),
('encrypted', '240s'),
('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'),
('unknown', '!I=0x00000200'),
('bodyLength2', '<I'),
('versionMinor', '<H'),
('versionMajor', '<H'),
('salt', '16s'),
('encrypted', ':'),
('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):
requestData = self.RequestV5(self.data)
decrypted = self.decryptRequest(requestData)
responseBuffer = self.serverLogic(decrypted['request'])
iv, encrypted = self.encryptResponse(requestData, decrypted, responseBuffer)
responseData = self.generateResponse(iv, encrypted, requestData)
return responseData
def decryptRequest(self, request):
encrypted = bytearray(enco(str(request['message']), 'latin-1'))
iv = bytearray(enco(request['message']['salt'], 'latin-1'))
moo = aes.AESModeOfOperation()
moo.aes.v6 = self.v6
decrypted = moo.decrypt(encrypted, 256, moo.ModeOfOperation["CBC"], self.key, moo.aes.KeySize["SIZE_128"], iv)
decrypted = aes.strip_PKCS7_padding(decrypted)
decrypted = bytes(bytearray(decrypted))
return self.DecryptedRequest(decrypted)
def encryptResponse(self, request, decrypted, response):
randomSalt = self.getRandomSalt()
result = hashlib.sha256(randomSalt).digest()
iv = bytearray(enco(request['message']['salt'], 'latin-1'))
randomStuff = bytearray(16)
for i in range(0,16):
randomStuff[i] = (bytearray(enco(decrypted['salt'], 'latin-1'))[i] ^ iv[i] ^ randomSalt[i]) & 0xff
responsedata = self.DecryptedResponse()
responsedata['response'] = response
responsedata['keys'] = bytes(randomStuff)
responsedata['hash'] = result
padded = aes.append_PKCS7_padding(enco(str(responsedata), 'latin-1'))
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)
return bytes(iv), bytes(bytearray(crypted))
def decryptResponse(self, response):
paddingLength = self.getPadding(response['bodyLength1'])
iv = bytearray(enco(response['salt'], 'latin-1'))
encrypted = bytearray(enco(response['encrypted'][:-paddingLength], 'latin-1'))
moo = aes.AESModeOfOperation()
moo.aes.v6 = self.v6
decrypted = moo.decrypt(encrypted, 256, moo.ModeOfOperation["CBC"], self.key, moo.aes.KeySize["SIZE_128"], iv)
decrypted = aes.strip_PKCS7_padding(decrypted)
decrypted = bytes(bytearray(decrypted))
return self.DecryptedResponse(decrypted)
def getRandomSalt(self):
return bytearray(random.getrandbits(8) for i in range(16))
def generateResponse(self, iv, encryptedResponse, requestData):
response = self.ResponseV5()
bodyLength = 2 + 2 + len(iv) + len(encryptedResponse)
response['bodyLength1'] = bodyLength
response['bodyLength2'] = bodyLength
response['versionMinor'] = requestData['versionMinor']
response['versionMajor'] = requestData['versionMajor']
response['salt'] = iv
response['encrypted'] = bytes(bytearray(encryptedResponse))
response['padding'] = bytes(bytearray(self.getPadding(bodyLength)))
ShellMessage.Process(16).run()
response = byterize(response)
loggersrv.info("KMS V%d Response: \n%s\n" % (self.ver, justify(response.dump(print_to_stdout = False))))
loggersrv.info("KMS V%d Structure Bytes: \n%s\n" % (self.ver, justify(deco(binascii.b2a_hex(enco(str(response), 'latin-1')), 'utf-8'))))
return str(response)
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)
dsalt = bytearray(dsalt)
decrypted = self.DecryptedRequest()
decrypted['salt'] = bytes(dsalt)
decrypted['request'] = requestBase
padded = aes.append_PKCS7_padding(enco(str(decrypted), 'latin-1'))
mode, orig_len, crypted = moo.encrypt(padded, moo.ModeOfOperation["CBC"], self.key, moo.aes.KeySize["SIZE_128"], esalt)
message = self.RequestV5.Message(bytes(bytearray(crypted)))
request = self.RequestV5()
bodyLength = 2 + 2 + len(message)
request['bodyLength1'] = bodyLength
request['bodyLength2'] = bodyLength
request['versionMinor'] = requestBase['versionMinor']
request['versionMajor'] = requestBase['versionMajor']
request['message'] = message
ShellMessage.Process(10).run()
request = byterize(request)
loggersrv.info("Request V%d Data: \n%s\n" % (self.ver, justify(request.dump(print_to_stdout = False))))
loggersrv.info("Request V%d: \n%s\n" % (self.ver, justify(deco(binascii.b2a_hex(enco(str(request), 'latin-1')), 'utf-8'))))
return request

108
py-kms/pykms_RequestV6.py Normal file
View file

@ -0,0 +1,108 @@
#!/usr/bin/env python3
import hashlib
import hmac
import struct
import pykms_Aes as aes
from pykms_Base import kmsBase
from pykms_RequestV5 import kmsRequestV5
from pykms_Structure import Structure
from pykms_Format import enco, deco
#---------------------------------------------------------------------------------------------------------------------------------------------------------
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()
result = hashlib.sha256(randomSalt).digest()
SaltC = bytearray(enco(request['message']['salt'], 'latin-1'))
DSaltC = bytearray(enco(decrypted['salt'], 'latin-1'))
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'] = bytes(randomStuff)
message['hash'] = result
message['xorSalts'] = bytes(XorSalts)
message['hwid'] = self.srv_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)
# DSaltS
DSaltS = bytearray(decry)
# HMacMsg
HMacMsg = bytearray(16)
for i in range(0,16):
HMacMsg[i] = (SaltS[i] ^ DSaltS[i]) & 0xff
HMacMsg.extend(enco(str(message), 'latin-1'))
# HMacKey
requestTime = decrypted['request']['requestTime']
HMacKey = self.getMACKey(requestTime)
HMac = hmac.new(HMacKey, bytes(HMacMsg), hashlib.sha256)
digest = HMac.digest()
responsedata = self.DecryptedResponse()
responsedata['message'] = message
responsedata['hmac'] = digest[16:]
padded = aes.append_PKCS7_padding(enco(str(responsedata), 'latin-1'))
mode, orig_len, crypted = moo.encrypt(padded, moo.ModeOfOperation["CBC"], self.key, moo.aes.KeySize["SIZE_128"], SaltS)
return bytes(SaltS), bytes(bytearray(crypted))
def getMACKey(self, t):
c1 = 0x00000022816889BD
c2 = 0x000000208CBAB5ED
c3 = 0x3156CD5AC628477A
i1 = (t // c1) & 0xFFFFFFFFFFFFFFFF
i2 = (i1 * c2) & 0xFFFFFFFFFFFFFFFF
seed = (i2 + c3) & 0xFFFFFFFFFFFFFFFF
sha256 = hashlib.sha256()
sha256.update(struct.pack("<Q", seed))
digest = sha256.digest()
return digest[16:]

45
py-kms/pykms_RpcBase.py Normal file
View file

@ -0,0 +1,45 @@
#!/usr/bin/env python3
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, srv_config):
self.data = data
self.srv_config = srv_config
def populate(self):
return self.generateResponse(self.parseRequest())
def parseRequest(self):
return {}

175
py-kms/pykms_RpcBind.py Normal file
View file

@ -0,0 +1,175 @@
#!/usr/bin/env python3
import logging
import binascii
import uuid
import pykms_RpcBase
from pykms_Dcerpc import MSRPCHeader, MSRPCBindAck
from pykms_Structure import Structure
from pykms_Format import justify, byterize, enco, deco, ShellMessage
#--------------------------------------------------------------------------------------------------------------------------------------------------------
loggersrv = logging.getLogger('logsrv')
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 = enco(self['TransferSyntaxUUID'], 'latin-1'))
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(pykms_RpcBase.rpcBase):
def parseRequest(self):
request = MSRPCHeader(self.data)
ShellMessage.Process(3).run()
request = byterize(request)
loggersrv.debug("RPC Bind Request Bytes: \n%s\n" % justify(deco(binascii.b2a_hex(self.data), 'utf-8')))
loggersrv.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, request):
response = MSRPCBindAck()
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.srv_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)
ShellMessage.Process(4).run()
response = byterize(response)
loggersrv.debug("RPC Bind Response: \n%s\n" % justify(response.dump(print_to_stdout = False)))
loggersrv.debug("RPC Bind Response Bytes: \n%s\n" % justify(deco(binascii.b2a_hex(enco(str(response), 'latin-1')), 'utf-8')))
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)))
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.srv_config['call_id']
request['pduData'] = str(bind)
ShellMessage.Process(0).run()
bind = byterize(bind)
request = byterize(request)
loggersrv.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))))
loggersrv.debug("RPC Bind Request Bytes: \n%s\n" % justify(deco(binascii.b2a_hex(enco(str(request), 'latin-1')), 'utf-8')))
return request
def parseResponse(self):
return response

View file

@ -0,0 +1,70 @@
#!/usr/bin/env python3
import binascii
import logging
import pykms_Base
import pykms_RpcBase
from pykms_Dcerpc import MSRPCRequestHeader, MSRPCRespHeader
from pykms_Format import justify, byterize, enco, deco, ShellMessage
#----------------------------------------------------------------------------------------------------------------------------------------------------------
loggersrv = logging.getLogger('logsrv')
class handler(pykms_RpcBase.rpcBase):
def parseRequest(self):
request = MSRPCRequestHeader(self.data)
ShellMessage.Process(14).run()
request = byterize(request)
loggersrv.debug("RPC Message Request Bytes: \n%s\n" % justify(binascii.b2a_hex(self.data).decode('utf-8')))
loggersrv.debug("RPC Message Request: \n%s\n" % justify(request.dump(print_to_stdout = False)))
return request
def generateResponse(self, request):
responseData = pykms_Base.generateKmsResponseData(request['pduData'], self.srv_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
ShellMessage.Process(17).run()
response = byterize(response)
loggersrv.debug("RPC Message Response: \n%s\n" % justify(response.dump(print_to_stdout = False)))
loggersrv.debug("RPC Message Response Bytes: \n%s\n" % justify(deco(binascii.b2a_hex(enco(str(response), 'latin-1')), 'utf-8')))
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.srv_config['call_id']
request['alloc_hint'] = len(self.data)
request['pduData'] = str(self.data)
ShellMessage.Process(11).run()
request = byterize(request)
loggersrv.debug("RPC Message Request: \n%s\n" % justify(request.dump(print_to_stdout = False)))
loggersrv.debug("RPC Message Request Bytes: \n%s\n" % justify(deco(binascii.b2a_hex(enco(str(request), 'latin-1')), 'utf-8')))
return request
def parseResponse(self):
return response

266
py-kms/pykms_Server.py Normal file
View file

@ -0,0 +1,266 @@
#!/usr/bin/env python3
import argparse
import binascii
import re
import sys
import socket
import uuid
import logging
import os
import errno
import threading
try:
# Python 2 import.
import SocketServer as socketserver
import Queue as Queue
except ImportError:
# Python 3 import.
import socketserver
import queue as Queue
import pykms_RpcBind, pykms_RpcRequest
from pykms_RpcBase import rpcBase
from pykms_Dcerpc import MSRPCHeader
from pykms_Misc import ValidLcid, logger_create
from pykms_Format import enco, deco, ShellMessage
srv_description = 'KMS Server Emulator written in Python'
srv_version = 'py-kms_2019-05-15'
srv_config = {}
##---------------------------------------------------------------------------------------------------------------------------------------------------------
class server_thread(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
self.queue = serverqueue
self.is_running = False
self.daemon = True
def run(self):
while True:
if not self.queue.empty():
item = self.queue.get()
if item == 'start':
self.is_running = True
# Check options.
server_check()
# Create and run threaded server.
self.server = server_create()
try:
self.server.serve_forever()
except KeyboardInterrupt:
sys.exit(0)
elif item == 'stop':
self.is_running = False
self.server = None
self.queue.task_done()
##-----------------------------------------------------------------------------------------------------------------------------------------------
loggersrv = logging.getLogger('logsrv')
# 'help' string - 'default' value - 'dest' string.
srv_options = {
'ip' : {'help' : 'The IP address to listen on. The default is \"0.0.0.0\" (all interfaces).', 'def' : "0.0.0.0", 'des' : "ip"},
'port' : {'help' : 'The network port to listen on. The default is \"1688\".', 'def' : 1688, 'des' : "port"},
'epid' : {'help' : 'Use this option to manually specify an ePID to use. If no ePID is specified, a random ePID will be auto generated.',
'def' : None, 'des' : "epid"},
'lcid' : {'help' : 'Use this option to manually specify an LCID for use with randomly generated ePIDs. Default is \"1033\" (en-us)',
'def' : 1033, 'des' : "lcid"},
'count' : {'help' : 'Use this option to specify the current client count. A number >=25 is required to enable activation of client OSes; \
for server OSes and Office >=5', 'def' : None, 'des' : "CurrentClientCount"},
'activation' : {'help' : 'Use this option to specify the activation interval (in minutes). Default is \"120\" minutes (2 hours).',
'def' : 120, 'des': "VLActivationInterval"},
'renewal' : {'help' : 'Use this option to specify the renewal interval (in minutes). Default is \"10080\" minutes (7 days).',
'def' : 1440 * 7, 'des' : "VLRenewalInterval"},
'sql' : {'help' : 'Use this option to store request information from unique clients in an SQLite database. Desactivated by default.',
'def' : False, 'des' : "sqlite"},
'hwid' : {'help' : 'Use this option 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.', 'def' : "364F463A8863D35F", 'des' : "hwid"},
'time' : {'help' : 'Disconnect clients after time of inactivity (in seconds). The default is \"30\" seconds', 'def' : 30, 'des' : "timeout"},
'llevel' : {'help' : 'Use this option to set a log level. The default is \"ERROR\".', 'def' : "ERROR", 'des' : "loglevel",
'choi' : ["CRITICAL", "ERROR", "WARNING", "INFO", "DEBUG", "MINI"]},
'lfile' : {'help' : 'Use this option to set or not an output log file. The default is \"pykms_logserver.log\" or type \"STDOUT\" to view log info on stdout.',
'def' : os.path.dirname(os.path.abspath( __file__ )) + "/pykms_logserver.log", 'des' : "logfile"},
'lsize' : {'help' : 'Use this flag to set a maximum size (in MB) to the output log file. Desactivated by default.', 'def' : 0, 'des': "logsize"},
}
def server_options():
parser = argparse.ArgumentParser(description = srv_description, epilog = 'version: ' + srv_version)
parser.add_argument("ip", nargs = "?", action = "store", default = srv_options['ip']['def'], help = srv_options['ip']['help'], type = str)
parser.add_argument("port", nargs = "?", action = "store", default = srv_options['port']['def'], help = srv_options['port']['help'], type = int)
parser.add_argument("-e", "--epid", dest = srv_options['epid']['des'], default = srv_options['epid']['def'], help = srv_options['epid']['help'], type = str)
parser.add_argument("-l", "--lcid", dest = srv_options['lcid']['des'], default = srv_options['lcid']['def'], help = srv_options['lcid']['help'], type = int)
parser.add_argument("-c", "--client-count", dest = srv_options['count']['des'] , default = srv_options['count']['def'],
help = srv_options['count']['help'], type = int)
parser.add_argument("-a", "--activation-interval", dest = srv_options['activation']['des'], default = srv_options['activation']['def'],
help = srv_options['activation']['help'], type = int)
parser.add_argument("-r", "--renewal-interval", dest = srv_options['renewal']['des'], default = srv_options['renewal']['def'],
help = srv_options['renewal']['help'], type = int)
parser.add_argument("-s", "--sqlite", dest = srv_options['sql']['des'], action = "store_const", const = True, default = srv_options['sql']['def'],
help = srv_options['sql']['help'])
parser.add_argument("-w", "--hwid", dest = srv_options['hwid']['des'], action = "store", default = srv_options['hwid']['def'],
help = srv_options['hwid']['help'], type = str)
parser.add_argument("-t", "--timeout", dest = srv_options['time']['des'], action = "store", default = srv_options['time']['def'],
help = srv_options['time']['help'], type = int)
parser.add_argument("-V", "--loglevel", dest = srv_options['llevel']['des'], action = "store", choices = srv_options['llevel']['choi'],
default = srv_options['llevel']['def'], help = srv_options['llevel']['help'], type = str)
parser.add_argument("-F", "--logfile", dest = srv_options['lfile']['des'], action = "store", default = srv_options['lfile']['def'],
help = srv_options['lfile']['help'], type = str)
parser.add_argument("-S", "--logsize", dest = srv_options['lsize']['des'], action = "store", default = srv_options['lsize']['def'],
help = srv_options['lsize']['help'], type = float)
srv_config.update(vars(parser.parse_args()))
def server_check():
# Setup hidden or not messages.
ShellMessage.view = ( False if srv_config['logfile'] == 'STDOUT' else True )
# Create log.
logger_create(loggersrv, srv_config, mode = 'a')
# Random HWID.
if srv_config['hwid'] == "RANDOM":
randomhwid = uuid.uuid4().hex
srv_config['hwid'] = randomhwid[:16]
# Sanitize HWID.
try:
srv_config['hwid'] = binascii.a2b_hex(re.sub(r'[^0-9a-fA-F]', '', srv_config['hwid'].strip('0x')))
if len(binascii.b2a_hex(srv_config['hwid'])) < 16:
loggersrv.error("HWID \"%s\" is invalid. Hex string is too short." % deco(binascii.b2a_hex(srv_config['hwid']), 'utf-8').upper())
return
elif len(binascii.b2a_hex(srv_config['hwid'])) > 16:
loggersrv.error("HWID \"%s\" is invalid. Hex string is too long." % deco(binascii.b2a_hex(srv_config['hwid']), 'utf-8').upper())
return
except TypeError:
loggersrv.error("HWID \"%s\" is invalid. Odd-length hex string." % deco(binascii.b2a_hex(srv_config['hwid']), 'utf-8').upper())
return
# Check LCID.
# http://stackoverflow.com/questions/3425294/how-to-detect-the-os-default-language-in-python
if not srv_config['lcid'] or (srv_config['lcid'] not in ValidLcid):
if hasattr(sys, 'implementation') and sys.implementation.name == 'cpython':
srv_config['lcid'] = 1033
elif os.name == 'nt':
import ctypes
srv_config['lcid'] = ctypes.windll.kernel32.GetUserDefaultUILanguage()
else:
import locale
try:
srv_config['lcid'] = next(k for k, v in locale.windows_locale.items() if v == locale.getdefaultlocale()[0])
except StopIteration:
srv_config['lcid'] = 1033
# Check sqlite.
try:
import sqlite3
except:
loggersrv.warning("Module \"sqlite3\" is not installed, database support disabled.")
srv_config['dbSupport'] = False
else:
srv_config['dbSupport'] = True
# Check port.
try:
p = srv_config['port']
if p > 65535:
loggersrv.error('Please enter a valid port number between 1 - 65535')
return
except Exception as e:
loggersrv.error('%s' %e)
return
def server_create():
socketserver.TCPServer.allow_reuse_address = True
server = socketserver.TCPServer((srv_config['ip'], srv_config['port']), kmsServer)
server.timeout = srv_config['timeout']
loggersrv.info("\n\nTCP server listening at %s on port %d." % (srv_config['ip'], srv_config['port']))
loggersrv.info("HWID: %s" % deco(binascii.b2a_hex(srv_config['hwid']), 'utf-8').upper())
return server
def srv_main_without_gui():
# Parse options.
server_options()
# Run threaded server.
serverqueue.put('start')
serverthread.join()
def srv_main_with_gui(width = 950, height = 660):
import pykms_GuiBase
root = pykms_GuiBase.KmsGui()
root.title(pykms_GuiBase.gui_description + ' ' + pykms_GuiBase.gui_version)
# Main window initial position.
## https://stackoverflow.com/questions/14910858/how-to-specify-where-a-tkinter-window-opens
ws = root.winfo_screenwidth()
hs = root.winfo_screenheight()
x = (ws / 2) - (width / 2)
y = (hs / 2) - (height / 2)
root.geometry('+%d+%d' %(x, y))
root.mainloop()
class kmsServer(socketserver.BaseRequestHandler):
def setup(self):
loggersrv.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.request.recv(1024)
except socket.error as e:
if e.errno == errno.ECONNRESET:
loggersrv.error("Connection reset by peer.")
break
else:
raise
if self.data == '' or not self.data:
loggersrv.warning("No data received !")
break
packetType = MSRPCHeader(self.data)['type']
if packetType == rpcBase.packetType['bindReq']:
loggersrv.info("RPC bind request received.")
ShellMessage.Process([-2, 2]).run()
handler = pykms_RpcBind.handler(self.data, srv_config)
elif packetType == rpcBase.packetType['request']:
loggersrv.info("Received activation request.")
ShellMessage.Process([-2, 13]).run()
handler = pykms_RpcRequest.handler(self.data, srv_config)
else:
loggersrv.error("Invalid RPC request type ", packetType)
break
res = enco(str(handler.populate()), 'latin-1')
self.request.send(res)
if packetType == rpcBase.packetType['bindReq']:
loggersrv.info("RPC bind acknowledged.")
ShellMessage.Process([-3, 5, 6]).run()
elif packetType == rpcBase.packetType['request']:
loggersrv.info("Responded to activation request.")
ShellMessage.Process([-3, 18, 19]).run()
break
def finish(self):
self.request.close()
loggersrv.info("Connection closed: %s:%d" % (self.client_address[0], self.client_address[1]))
serverqueue = Queue.Queue(maxsize = 0)
serverthread = server_thread()
serverthread.start()
if __name__ == "__main__":
if sys.stdout.isatty():
srv_main_without_gui()
else:
srv_main_with_gui()

96
py-kms/pykms_Sql.py Normal file
View file

@ -0,0 +1,96 @@
#!/usr/bin/env python3
import logging
# sqlite3 is optional.
try:
import sqlite3
except ImportError:
pass
#--------------------------------------------------------------------------------------------------------------------------------------------------------
logger = logging.getLogger('root')
def sql_initialize():
dbName = 'clients.db'
if not os.path.isfile(dbName):
# Initialize the database.
con = None
try:
con = sqlite3.connect(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:
logger.error("Error %s:" % e.args[0])
sys.exit(1)
finally:
if con:
con.commit()
con.close()
return dbName
def sql_update(dbName, infoDict):
con = None
try:
con = sqlite3.connect(dbName)
cur = con.cursor()
cur.execute("SELECT * FROM clients WHERE clientMachineId=:clientMachineId;", infoDict)
try:
data = cur.fetchone()
if not data:
# Insert row.
cur.execute("INSERT INTO clients (clientMachineId, machineName, applicationId, \
skuId, licenseStatus, lastRequestTime, requestCount) VALUES (:clientMachineId, :machineName, :appId, :skuId, :licenseStatus, :requestTime, 1);", infoDict)
else:
# Update 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:
logger.error("Error %s:" % e.args[0])
except sqlite3.Error as e:
logger.error("Error %s:" % e.args[0])
sys.exit(1)
finally:
if con:
con.commit()
con.close()
def sql_update_epid(dbName, kmsRequest, response):
cmid = str(kmsRequest['clientMachineId'].get())
con = None
try:
con = sqlite3.connect(self.dbName)
cur = con.cursor()
cur.execute("SELECT * FROM clients WHERE clientMachineId=?;", [cmid])
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')),
cmid))
except sqlite3.Error as e:
logger.error("Error %s:" % e.args[0])
except sqlite3.Error as e:
logger.error("Error %s:" % e.args[0])
sys.exit(1)
finally:
if con:
con.commit()
con.close()
return response

763
py-kms/pykms_Structure.py Normal file
View file

@ -0,0 +1,763 @@
#!/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.
#
"""
Stripped down version of: https://github.com/CoreSecurity/impacket/blob/python3/impacket/structure.py
with modifications in the function dump(...).
"""
from __future__ import print_function
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
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 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()