/*!
* @file syskey.c
* @brief Definitions for functions to retrieve the SYSKEY from the Registry
*/
#include "extapi.h"

#include <inttypes.h>
#include <wincrypt.h>
#include "syskey.h"
#include "ntds_decrypt.h"
#include "ntds_jet.h"
#include "ntds.h"

/*!
* @brief Get individual component of the SysKey from the Registry.
* @param lsaHandle Handle to the LSA Registry Key
* @param subkeyName String containing the name of the Subkey to read from.
* @param tmpSysKey Pointer to the string of the Syskey we are building
* @returns Indication of sucess or failure.
*/
BOOL get_syskey_component(HKEY lsaHandle, char subkeyName[255], unsigned char *tmpSysKey)
{
	DWORD sizeData = 9;
	long regStatus;
	HKEY subkeyHandle;
	unsigned char tmpVal[16];
	intmax_t byteComponent = 0;

	regStatus = RegOpenKeyEx(lsaHandle, subkeyName, 0, KEY_READ, &subkeyHandle);
	if (regStatus != ERROR_SUCCESS) {
		return FALSE;
	}
	regStatus = RegQueryInfoKey(subkeyHandle, (LPSTR)&tmpVal, &sizeData, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
	if (regStatus != ERROR_SUCCESS) {
		return FALSE;
	}
	byteComponent = strtoimax(tmpVal, NULL, 16);
	strncat_s(tmpSysKey, 17, (char *)&byteComponent, 4);
	RegCloseKey(subkeyHandle);
	return TRUE;
}

/*!
* @brief Retrieves and assembled the SYSKEY from the Registry
* @param sysKey Pointer to the string of the Syskey we are building
* @returns Indication of sucess or failure.
*/
BOOL get_syskey(unsigned char *sysKey)
{
	unsigned char tmpSysKey[17];
	unsigned char interimSysKey[17];
	long regStatus;
	DWORD disposition = 0;
	HKEY lsaHandle;
	memset(&tmpSysKey, 0, sizeof(tmpSysKey));
	memset(&interimSysKey, 0, sizeof(tmpSysKey));

	//Used for descrambling the bytes of the SYSKEY (absurd isn't it?)
	BYTE syskeyDescrambler[16] = { 0x0b, 0x06, 0x07, 0x01, 0x08, 0x0a, 0x0e, 0x00, 0x03, 0x05, 0x02, 0x0f, 0x0d, 0x09, 0x0c, 0x04 };

	regStatus = RegCreateKeyEx(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Control\\Lsa", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_READ, NULL, &lsaHandle, &disposition);
	if (regStatus != ERROR_SUCCESS) {
		return FALSE;
	}
	if (disposition == REG_CREATED_NEW_KEY) {
		RegCloseKey(lsaHandle);
		return FALSE;
	}
	if (!get_syskey_component(lsaHandle, "JD", tmpSysKey)) {
		return FALSE;
	}
	if (!get_syskey_component(lsaHandle, "Skew1", tmpSysKey)) {
		return FALSE;
	}
	if (!get_syskey_component(lsaHandle, "GBG", tmpSysKey)) {
		return FALSE;
	}
	if (!get_syskey_component(lsaHandle, "Data", tmpSysKey)) {
		return FALSE;
	}

	for (int i = 0; i < 16; i++) {
		interimSysKey[i] = tmpSysKey[syskeyDescrambler[i]];
	}
	strncpy_s(sysKey, 17, interimSysKey, 16);
	RegCloseKey(lsaHandle);
	return TRUE;
}