485 lines
9.5 KiB
C++
485 lines
9.5 KiB
C++
//#include <StdAfx.h>
|
|
#include "AdmtCrypt.h"
|
|
|
|
#include <NtSecApi.h>
|
|
|
|
#pragma comment( lib, "AdvApi32.lib" )
|
|
|
|
|
|
namespace AdmtCrypt2
|
|
{
|
|
|
|
#define SESSION_KEY_SIZE 16 // in bytes
|
|
|
|
HCRYPTKEY __stdcall DeriveEncryptionKey(HCRYPTPROV hProvider);
|
|
bool __stdcall IsDataMatchHash(HCRYPTPROV hProvider, const _variant_t& vntData, const _variant_t& vntHash);
|
|
|
|
// Provider Methods
|
|
|
|
HCRYPTKEY __stdcall DeriveKey(HCRYPTPROV hProvider, const _variant_t& vntBytes);
|
|
HCRYPTHASH __stdcall CreateHash(HCRYPTPROV hProvider);
|
|
bool __stdcall GenRandom(HCRYPTPROV hProvider, BYTE* pbData, DWORD cbData);
|
|
|
|
// Key Methods
|
|
|
|
void __stdcall DestroyKey(HCRYPTKEY hKey);
|
|
bool __stdcall Decrypt(HCRYPTKEY hKey, const _variant_t& vntEncrypted, _variant_t& vntDecrypted);
|
|
|
|
// Hash Methods
|
|
|
|
void __stdcall DestroyHash(HCRYPTHASH hHash);
|
|
bool __stdcall HashData(HCRYPTHASH hHash, const _variant_t& vntData);
|
|
|
|
// Miscellaneous Helpers
|
|
|
|
bool __stdcall RetrieveEncryptionBytes(_variant_t& vntBytes);
|
|
|
|
// Variant Helpers
|
|
|
|
bool __stdcall CreateByteArray(DWORD cb, _variant_t& vntByteArray);
|
|
|
|
}
|
|
|
|
using namespace AdmtCrypt2;
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Source Crypt API
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
// AdmtAcquireContext Method
|
|
|
|
HCRYPTPROV __stdcall AdmtAcquireContext()
|
|
{
|
|
HCRYPTPROV hProvider = 0;
|
|
|
|
BOOL bAcquire = CryptAcquireContext(
|
|
&hProvider,
|
|
NULL,
|
|
MS_ENHANCED_PROV,
|
|
PROV_RSA_FULL,
|
|
CRYPT_MACHINE_KEYSET|CRYPT_VERIFYCONTEXT
|
|
);
|
|
|
|
if (!bAcquire)
|
|
{
|
|
hProvider = 0;
|
|
}
|
|
|
|
return hProvider;
|
|
}
|
|
|
|
|
|
// AdmtReleaseContext Method
|
|
|
|
void __stdcall AdmtReleaseContext(HCRYPTPROV hProvider)
|
|
{
|
|
if (hProvider)
|
|
{
|
|
CryptReleaseContext(hProvider, 0);
|
|
}
|
|
}
|
|
|
|
|
|
// AdmtImportSessionKey Method
|
|
|
|
HCRYPTKEY __stdcall AdmtImportSessionKey(HCRYPTPROV hProvider, const _variant_t& vntEncryptedSessionBytes)
|
|
{
|
|
HCRYPTKEY hSessionKey = 0;
|
|
|
|
if (hProvider && (vntEncryptedSessionBytes.vt == (VT_UI1|VT_ARRAY)) && ((vntEncryptedSessionBytes.parray != NULL)))
|
|
{
|
|
HCRYPTKEY hEncryptionKey = DeriveEncryptionKey(hProvider);
|
|
|
|
if (hEncryptionKey)
|
|
{
|
|
_variant_t vntDecryptedSessionBytes;
|
|
|
|
if (Decrypt(hEncryptionKey, vntEncryptedSessionBytes, vntDecryptedSessionBytes))
|
|
{
|
|
if (vntDecryptedSessionBytes.parray->rgsabound[0].cElements > SESSION_KEY_SIZE)
|
|
{
|
|
// extract session key bytes
|
|
|
|
_variant_t vntBytes;
|
|
|
|
if (CreateByteArray(SESSION_KEY_SIZE, vntBytes))
|
|
{
|
|
memcpy(vntBytes.parray->pvData, vntDecryptedSessionBytes.parray->pvData, SESSION_KEY_SIZE);
|
|
|
|
// extract hash of session key bytes
|
|
|
|
_variant_t vntHashValue;
|
|
|
|
DWORD cbHashValue = vntDecryptedSessionBytes.parray->rgsabound[0].cElements - SESSION_KEY_SIZE;
|
|
|
|
if (CreateByteArray(cbHashValue, vntHashValue))
|
|
{
|
|
memcpy(vntHashValue.parray->pvData, (BYTE*)vntDecryptedSessionBytes.parray->pvData + SESSION_KEY_SIZE, cbHashValue);
|
|
|
|
if (IsDataMatchHash(hProvider, vntBytes, vntHashValue))
|
|
{
|
|
hSessionKey = DeriveKey(hProvider, vntBytes);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
}
|
|
}
|
|
|
|
DestroyKey(hEncryptionKey);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
}
|
|
|
|
return hSessionKey;
|
|
}
|
|
|
|
|
|
// AdmtDecrypt Method
|
|
|
|
_bstr_t __stdcall AdmtDecrypt(HCRYPTKEY hSessionKey, const _variant_t& vntEncrypted)
|
|
{
|
|
BSTR bstr = NULL;
|
|
|
|
_variant_t vntDecrypted;
|
|
|
|
if (Decrypt(hSessionKey, vntEncrypted, vntDecrypted))
|
|
{
|
|
HRESULT hr = BstrFromVector(vntDecrypted.parray, &bstr);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
}
|
|
|
|
return bstr;
|
|
}
|
|
|
|
|
|
// AdmtDestroyKey Method
|
|
|
|
void __stdcall AdmtDestroyKey(HCRYPTKEY hKey)
|
|
{
|
|
DestroyKey(hKey);
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Private Helpers
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
namespace AdmtCrypt2
|
|
{
|
|
|
|
|
|
HCRYPTKEY __stdcall DeriveEncryptionKey(HCRYPTPROV hProvider)
|
|
{
|
|
HCRYPTKEY hKey = 0;
|
|
|
|
_variant_t vntBytes;
|
|
|
|
if (RetrieveEncryptionBytes(vntBytes))
|
|
{
|
|
hKey = DeriveKey(hProvider, vntBytes);
|
|
}
|
|
|
|
return hKey;
|
|
}
|
|
|
|
|
|
bool __stdcall IsDataMatchHash(HCRYPTPROV hProvider, const _variant_t& vntData, const _variant_t& vntHash)
|
|
{
|
|
bool bMatch = false;
|
|
|
|
HCRYPTHASH hHash = CreateHash(hProvider);
|
|
|
|
if (hHash)
|
|
{
|
|
if (HashData(hHash, vntData))
|
|
{
|
|
DWORD dwSizeA;
|
|
DWORD cbSize = sizeof(DWORD);
|
|
|
|
if (CryptGetHashParam(hHash, HP_HASHSIZE, (BYTE*)&dwSizeA, &cbSize, 0))
|
|
{
|
|
DWORD dwSizeB = vntHash.parray->rgsabound[0].cElements;
|
|
|
|
if (dwSizeA == dwSizeB)
|
|
{
|
|
try
|
|
{
|
|
BYTE* pbA = (BYTE*) _alloca(dwSizeA);
|
|
|
|
if (CryptGetHashParam(hHash, HP_HASHVAL, pbA, &dwSizeA, 0))
|
|
{
|
|
BYTE* pbB = (BYTE*) vntHash.parray->pvData;
|
|
|
|
if (memcmp(pbA, pbB, dwSizeA) == 0)
|
|
{
|
|
bMatch = true;
|
|
}
|
|
}
|
|
}
|
|
catch (...)
|
|
{
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return bMatch;
|
|
}
|
|
|
|
|
|
// Provider Methods
|
|
|
|
|
|
HCRYPTKEY __stdcall DeriveKey(HCRYPTPROV hProvider, const _variant_t& vntBytes)
|
|
{
|
|
HCRYPTKEY hKey = 0;
|
|
|
|
HCRYPTHASH hHash = CreateHash(hProvider);
|
|
|
|
if (hHash)
|
|
{
|
|
if (HashData(hHash, vntBytes))
|
|
{
|
|
if (!CryptDeriveKey(hProvider, CALG_3DES, hHash, 0, &hKey))
|
|
{
|
|
hKey = 0;
|
|
}
|
|
}
|
|
|
|
DestroyHash(hHash);
|
|
}
|
|
|
|
return hKey;
|
|
}
|
|
|
|
|
|
HCRYPTHASH __stdcall CreateHash(HCRYPTPROV hProvider)
|
|
{
|
|
HCRYPTHASH hHash;
|
|
|
|
if (!CryptCreateHash(hProvider, CALG_SHA1, 0, 0, &hHash))
|
|
{
|
|
hHash = 0;
|
|
}
|
|
|
|
return hHash;
|
|
}
|
|
|
|
|
|
bool __stdcall GenRandom(HCRYPTPROV hProvider, BYTE* pbData, DWORD cbData)
|
|
{
|
|
return CryptGenRandom(hProvider, cbData, pbData) ? true : false;
|
|
}
|
|
|
|
|
|
// Key Methods --------------------------------------------------------------
|
|
|
|
|
|
// DestroyKey Method
|
|
|
|
void __stdcall DestroyKey(HCRYPTKEY hKey)
|
|
{
|
|
if (hKey)
|
|
{
|
|
CryptDestroyKey(hKey);
|
|
}
|
|
}
|
|
|
|
|
|
// Decrypt Method
|
|
|
|
bool __stdcall Decrypt(HCRYPTKEY hKey, const _variant_t& vntEncrypted, _variant_t& vntDecrypted)
|
|
{
|
|
bool bDecrypted = false;
|
|
|
|
_variant_t vnt = vntEncrypted;
|
|
|
|
if ((vnt.vt == (VT_UI1|VT_ARRAY)) && (vnt.parray != NULL))
|
|
{
|
|
// decrypt data
|
|
|
|
BYTE* pb = (BYTE*) vnt.parray->pvData;
|
|
DWORD cb = vnt.parray->rgsabound[0].cElements;
|
|
|
|
if (CryptDecrypt(hKey, NULL, TRUE, 0, pb, &cb))
|
|
{
|
|
// create decrypted byte array
|
|
// the number of decrypted bytes may be less than
|
|
// the number of encrypted bytes
|
|
|
|
vntDecrypted.parray = SafeArrayCreateVector(VT_UI1, 0, cb);
|
|
|
|
if (vntDecrypted.parray != NULL)
|
|
{
|
|
vntDecrypted.vt = VT_UI1|VT_ARRAY;
|
|
|
|
memcpy(vntDecrypted.parray->pvData, vnt.parray->pvData, cb);
|
|
|
|
bDecrypted = true;
|
|
}
|
|
else
|
|
{
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
}
|
|
|
|
return bDecrypted;
|
|
}
|
|
|
|
|
|
// Hash Methods -------------------------------------------------------------
|
|
|
|
|
|
// DestroyHash Method
|
|
|
|
void __stdcall DestroyHash(HCRYPTHASH hHash)
|
|
{
|
|
if (hHash)
|
|
{
|
|
CryptDestroyHash(hHash);
|
|
}
|
|
}
|
|
|
|
|
|
// HashData Method
|
|
|
|
bool __stdcall HashData(HCRYPTHASH hHash, const _variant_t& vntData)
|
|
{
|
|
bool bHash = false;
|
|
|
|
if ((vntData.vt == (VT_UI1|VT_ARRAY)) && ((vntData.parray != NULL)))
|
|
{
|
|
if (CryptHashData(hHash, (BYTE*)vntData.parray->pvData, vntData.parray->rgsabound[0].cElements, 0))
|
|
{
|
|
bHash = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
}
|
|
|
|
return bHash;
|
|
}
|
|
|
|
|
|
// Miscellaneous Helpers ----------------------------------------------------
|
|
|
|
|
|
// RetrieveEncryptionBytes Method
|
|
|
|
bool __stdcall RetrieveEncryptionBytes(_variant_t& vntBytes)
|
|
{
|
|
// private data key identifier
|
|
_TCHAR c_szIdPrefix[] = _T("L$6A2899C0-CECE-459A-B5EB-7ED04DE61388");
|
|
const USHORT c_cbIdPrefix = sizeof(c_szIdPrefix) - sizeof(_TCHAR);
|
|
|
|
bool bRetrieve = false;
|
|
|
|
// open policy object
|
|
|
|
LSA_HANDLE hPolicy;
|
|
|
|
LSA_OBJECT_ATTRIBUTES lsaoa = { sizeof(LSA_OBJECT_ATTRIBUTES), NULL, NULL, 0, NULL, NULL };
|
|
|
|
NTSTATUS ntsStatus = LsaOpenPolicy(NULL, &lsaoa, POLICY_GET_PRIVATE_INFORMATION, &hPolicy);
|
|
|
|
if (LSA_SUCCESS(ntsStatus))
|
|
{
|
|
// retrieve data
|
|
|
|
LSA_UNICODE_STRING lsausKey = { c_cbIdPrefix, c_cbIdPrefix, c_szIdPrefix };
|
|
PLSA_UNICODE_STRING plsausData;
|
|
|
|
ntsStatus = LsaRetrievePrivateData(hPolicy, &lsausKey, &plsausData);
|
|
|
|
if (LSA_SUCCESS(ntsStatus))
|
|
{
|
|
vntBytes.Clear();
|
|
|
|
vntBytes.parray = SafeArrayCreateVector(VT_UI1, 0, plsausData->Length);
|
|
|
|
if (vntBytes.parray != NULL)
|
|
{
|
|
vntBytes.vt = VT_UI1|VT_ARRAY;
|
|
|
|
memcpy(vntBytes.parray->pvData, plsausData->Buffer, plsausData->Length);
|
|
|
|
bRetrieve = true;
|
|
}
|
|
else
|
|
{
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
|
|
LsaFreeMemory(plsausData);
|
|
}
|
|
else
|
|
{
|
|
SetLastError(LsaNtStatusToWinError(ntsStatus));
|
|
}
|
|
|
|
// close policy object
|
|
|
|
LsaClose(hPolicy);
|
|
}
|
|
else
|
|
{
|
|
SetLastError(LsaNtStatusToWinError(ntsStatus));
|
|
}
|
|
|
|
return bRetrieve;
|
|
}
|
|
|
|
|
|
// Variant Helpers ----------------------------------------------------------
|
|
|
|
|
|
// CreateByteArray Method
|
|
|
|
bool __stdcall CreateByteArray(DWORD cb, _variant_t& vntByteArray)
|
|
{
|
|
bool bCreate = false;
|
|
|
|
vntByteArray.Clear();
|
|
|
|
vntByteArray.parray = SafeArrayCreateVector(VT_UI1, 0, cb);
|
|
|
|
if (vntByteArray.parray)
|
|
{
|
|
bCreate = true;
|
|
}
|
|
else
|
|
{
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
|
|
vntByteArray.vt = VT_UI1|VT_ARRAY;
|
|
|
|
return bCreate;
|
|
}
|
|
|
|
|
|
}
|