You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1185 lines
25 KiB
1185 lines
25 KiB
#include <StdAfx.h>
|
|
#include "AdmtCrypt.h"
|
|
#include "Array.h"
|
|
|
|
#include <NtSecApi.h>
|
|
|
|
#pragma comment( lib, "AdvApi32.lib" )
|
|
|
|
|
|
namespace
|
|
{
|
|
|
|
void __stdcall CreateByteArray(DWORD cb, _variant_t& vntByteArray)
|
|
{
|
|
vntByteArray.Clear();
|
|
|
|
vntByteArray.parray = SafeArrayCreateVector(VT_UI1, 0, cb);
|
|
|
|
if (vntByteArray.parray == NULL)
|
|
{
|
|
_com_issue_error(E_OUTOFMEMORY);
|
|
}
|
|
|
|
vntByteArray.vt = VT_UI1|VT_ARRAY;
|
|
}
|
|
|
|
_variant_t operator +(const _variant_t& vntByteArrayA, const _variant_t& vntByteArrayB)
|
|
{
|
|
_variant_t vntByteArrayC;
|
|
|
|
// validate parameters
|
|
|
|
if ((vntByteArrayA.vt != (VT_UI1|VT_ARRAY)) || ((vntByteArrayA.parray == NULL)))
|
|
{
|
|
_com_issue_error(E_INVALIDARG);
|
|
}
|
|
|
|
if ((vntByteArrayB.vt != (VT_UI1|VT_ARRAY)) || ((vntByteArrayB.parray == NULL)))
|
|
{
|
|
_com_issue_error(E_INVALIDARG);
|
|
}
|
|
|
|
// concatenate byte arrays
|
|
|
|
DWORD cbA = vntByteArrayA.parray->rgsabound[0].cElements;
|
|
DWORD cbB = vntByteArrayB.parray->rgsabound[0].cElements;
|
|
|
|
CreateByteArray(cbA + cbB, vntByteArrayC);
|
|
|
|
memcpy(vntByteArrayC.parray->pvData, vntByteArrayA.parray->pvData, cbA);
|
|
memcpy((BYTE*)vntByteArrayC.parray->pvData + cbA, vntByteArrayB.parray->pvData, cbB);
|
|
|
|
return vntByteArrayC;
|
|
}
|
|
|
|
#ifdef _DEBUG
|
|
|
|
_bstr_t __stdcall DebugByteArray(const _variant_t& vnt)
|
|
{
|
|
_bstr_t strArray;
|
|
|
|
if ((vnt.vt == (VT_UI1|VT_ARRAY)) && ((vnt.parray != NULL)))
|
|
{
|
|
_TCHAR szArray[256] = _T("");
|
|
|
|
DWORD c = vnt.parray->rgsabound[0].cElements;
|
|
BYTE* pb = (BYTE*) vnt.parray->pvData;
|
|
|
|
for (DWORD i = 0; i < c; i++, pb++)
|
|
{
|
|
_TCHAR sz[48];
|
|
wsprintf(sz, _T("%02X"), (UINT)(USHORT)*pb);
|
|
|
|
if (i > 0)
|
|
{
|
|
_tcscat(szArray, _T(" "));
|
|
}
|
|
|
|
_tcscat(szArray, sz);
|
|
}
|
|
|
|
strArray = szArray;
|
|
}
|
|
|
|
return strArray;
|
|
}
|
|
|
|
#define TRACE_BUFFER_SIZE 1024
|
|
|
|
void _cdecl Trace(LPCTSTR pszFormat, ...)
|
|
{
|
|
_TCHAR szMessage[TRACE_BUFFER_SIZE];
|
|
|
|
if (pszFormat)
|
|
{
|
|
va_list args;
|
|
va_start(args, pszFormat);
|
|
|
|
_vsntprintf(szMessage, TRACE_BUFFER_SIZE, pszFormat, args);
|
|
|
|
va_end(args);
|
|
|
|
#if 0
|
|
OutputDebugString(szMessage);
|
|
#else
|
|
HANDLE hFile = CreateFile(L"C:\\AdmtCrypt.log", GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
|
|
if (hFile != INVALID_HANDLE_VALUE)
|
|
{
|
|
SetFilePointer(hFile, 0, NULL, FILE_END);
|
|
DWORD dwWritten;
|
|
WriteFile(hFile, szMessage, _tcslen(szMessage) * sizeof(_TCHAR), &dwWritten, NULL);
|
|
CloseHandle(hFile);
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
#else
|
|
|
|
_bstr_t __stdcall DebugByteArray(const _variant_t& vnt)
|
|
{
|
|
return _T("");
|
|
}
|
|
|
|
void _cdecl Trace(LPCTSTR pszFormat, ...)
|
|
{
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Target Crypt Class
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
// Constructor
|
|
|
|
CTargetCrypt::CTargetCrypt()
|
|
{
|
|
Trace(_T("CTargetCrypt::CTargetCrypt()\r\n"));
|
|
}
|
|
|
|
|
|
// Destructor
|
|
|
|
CTargetCrypt::~CTargetCrypt()
|
|
{
|
|
Trace(_T("CTargetCrypt::~CTargetCrypt()\r\n"));
|
|
}
|
|
|
|
|
|
// CreateEncryptionKey Method
|
|
|
|
_variant_t CTargetCrypt::CreateEncryptionKey(LPCTSTR pszKeyId, LPCTSTR pszPassword)
|
|
{
|
|
Trace(_T("CreateEncryptionKey(pszKeyId='%s', pszPassword='%s')\r\n"), pszKeyId, pszPassword);
|
|
|
|
// generate encryption key bytes
|
|
|
|
_variant_t vntBytes = GenerateRandom(ENCRYPTION_KEY_SIZE);
|
|
|
|
Trace(_T(" vntBytes={ %s }\r\n"), (LPCTSTR)DebugByteArray(vntBytes));
|
|
|
|
// store encryption key bytes
|
|
|
|
StoreBytes(pszKeyId, vntBytes);
|
|
|
|
// create key from password
|
|
|
|
CCryptHash hashPassword(CreateHash(CALG_SHA1));
|
|
|
|
if (pszPassword && pszPassword[0])
|
|
{
|
|
hashPassword.Hash(pszPassword);
|
|
}
|
|
else
|
|
{
|
|
BYTE b = 0;
|
|
hashPassword.Hash(&b, 1);
|
|
}
|
|
|
|
CCryptKey keyPassword(DeriveKey(CALG_3DES, hashPassword));
|
|
|
|
_variant_t vntPasswordFlag;
|
|
CreateByteArray(1, vntPasswordFlag);
|
|
*((BYTE*)vntPasswordFlag.parray->pvData) = (pszPassword && pszPassword[0]) ? 0xFF : 0x00;
|
|
|
|
// concatenate encryption key bytes and hash of encryption key bytes
|
|
|
|
CCryptHash hashBytes(CreateHash(CALG_SHA1));
|
|
hashBytes.Hash(vntBytes);
|
|
|
|
_variant_t vntDecrypted = vntBytes + hashBytes.GetValue();
|
|
|
|
// Trace(_T(" vntDecrypted={ %s }\n"), (LPCTSTR)DebugByteArray(vntDecrypted));
|
|
|
|
// encrypt bytes / hash pair
|
|
|
|
_variant_t vntEncrypted = keyPassword.Encrypt(NULL, true, vntDecrypted);
|
|
|
|
// Trace(_T(" vntEncrypted={ %s }\n"), (LPCTSTR)DebugByteArray(vntEncrypted));
|
|
|
|
SecureZeroMemory(GET_BYTE_ARRAY_DATA(vntBytes), GET_BYTE_ARRAY_SIZE(vntBytes));
|
|
SecureZeroMemory(GET_BYTE_ARRAY_DATA(vntDecrypted), GET_BYTE_ARRAY_SIZE(vntDecrypted));
|
|
|
|
|
|
return vntPasswordFlag + vntEncrypted;
|
|
}
|
|
|
|
|
|
// CreateSession Method
|
|
|
|
_variant_t CTargetCrypt::CreateSession(LPCTSTR pszKeyId)
|
|
{
|
|
Trace(_T("CreateSession(pszKeyId='%s')\r\n"), pszKeyId);
|
|
|
|
// get encryption key
|
|
|
|
CCryptHash hashEncryption(CreateHash(CALG_SHA1));
|
|
hashEncryption.Hash(RetrieveBytes(pszKeyId));
|
|
|
|
CCryptKey keyEncryption(DeriveKey(CALG_3DES, hashEncryption));
|
|
|
|
// generate session key bytes
|
|
|
|
_variant_t vntBytes = GenerateRandom(SESSION_KEY_SIZE);
|
|
|
|
// create session key
|
|
|
|
CCryptHash hash(CreateHash(CALG_SHA1));
|
|
hash.Hash(vntBytes);
|
|
|
|
m_keySession.Attach(DeriveKey(CALG_3DES, hash));
|
|
|
|
// concatenate session key bytes and hash of session key bytes
|
|
|
|
_variant_t vntDecrypted = vntBytes + hash.GetValue();
|
|
|
|
// encrypt session bytes and include hash
|
|
_variant_t varEncrypted = keyEncryption.Encrypt(NULL, true, vntDecrypted);
|
|
|
|
SecureZeroMemory(GET_BYTE_ARRAY_DATA(vntBytes), GET_BYTE_ARRAY_SIZE(vntBytes));
|
|
SecureZeroMemory(GET_BYTE_ARRAY_DATA(vntDecrypted), GET_BYTE_ARRAY_SIZE(vntDecrypted));
|
|
|
|
return varEncrypted;
|
|
}
|
|
|
|
|
|
// Encrypt Method
|
|
|
|
_variant_t CTargetCrypt::Encrypt(_bstr_t strData)
|
|
{
|
|
Trace(_T("Encrypt(strData='%s')\r\n"), (LPCTSTR)strData);
|
|
|
|
// convert string to byte array
|
|
|
|
_variant_t vnt;
|
|
|
|
HRESULT hr = VectorFromBstr(strData, &vnt.parray);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
_com_issue_error(hr);
|
|
}
|
|
|
|
vnt.vt = VT_UI1|VT_ARRAY;
|
|
|
|
// encrypt data
|
|
|
|
_variant_t varEncrypted = m_keySession.Encrypt(NULL, true, vnt);
|
|
|
|
SecureZeroMemory(GET_BYTE_ARRAY_DATA(vnt), GET_BYTE_ARRAY_SIZE(vnt));
|
|
|
|
return varEncrypted;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Source Crypt Class
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
// Constructor
|
|
|
|
CSourceCrypt::CSourceCrypt()
|
|
{
|
|
Trace(_T("CSourceCrypt::CSourceCrypt()\r\n"));
|
|
}
|
|
|
|
|
|
// Destructor
|
|
|
|
CSourceCrypt::~CSourceCrypt()
|
|
{
|
|
Trace(_T("CSourceCrypt::~CSourceCrypt()\r\n"));
|
|
}
|
|
|
|
|
|
// ImportEncryptionKey Method
|
|
|
|
void CSourceCrypt::ImportEncryptionKey(const _variant_t& vntEncryptedKey, LPCTSTR pszPassword)
|
|
{
|
|
Trace(_T("ImportEncryptionKey(vntEncryptedKey={ %s }, pszPassword='%s')\r\n"), (LPCTSTR)DebugByteArray(vntEncryptedKey), pszPassword);
|
|
|
|
// validate parameters
|
|
|
|
if ((vntEncryptedKey.vt != (VT_UI1|VT_ARRAY)) || ((vntEncryptedKey.parray == NULL)))
|
|
{
|
|
_com_issue_error(E_INVALIDARG);
|
|
}
|
|
|
|
// extract password flag and verify with password
|
|
|
|
bool bPassword = *((BYTE*)vntEncryptedKey.parray->pvData) ? true : false;
|
|
|
|
if (bPassword)
|
|
{
|
|
if ((pszPassword == NULL) || (pszPassword[0] == NULL))
|
|
{
|
|
_com_issue_error(HRESULT_FROM_WIN32(ERROR_INVALID_PASSWORD));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (pszPassword && pszPassword[0])
|
|
{
|
|
_com_issue_error(HRESULT_FROM_WIN32(ERROR_INVALID_PASSWORD));
|
|
}
|
|
}
|
|
|
|
// create key from password
|
|
|
|
CCryptHash hashPassword(CreateHash(CALG_SHA1));
|
|
|
|
if (pszPassword && pszPassword[0])
|
|
{
|
|
hashPassword.Hash(pszPassword);
|
|
}
|
|
else
|
|
{
|
|
BYTE b = 0;
|
|
hashPassword.Hash(&b, 1);
|
|
}
|
|
|
|
CCryptKey keyPassword(DeriveKey(CALG_3DES, hashPassword));
|
|
|
|
// encrypted data
|
|
|
|
_variant_t vntEncrypted;
|
|
DWORD cbEncrypted = vntEncryptedKey.parray->rgsabound[0].cElements - 1;
|
|
CreateByteArray(cbEncrypted, vntEncrypted);
|
|
memcpy(vntEncrypted.parray->pvData, (BYTE*)vntEncryptedKey.parray->pvData + 1, cbEncrypted);
|
|
|
|
// Trace(_T(" vntEncrypted={ %s }\n"), (LPCTSTR)DebugByteArray(vntEncrypted));
|
|
|
|
// decrypt encryption key bytes plus hash
|
|
|
|
_variant_t vntDecrypted = keyPassword.Decrypt(NULL, true, vntEncrypted);
|
|
|
|
// Trace(_T(" vntDecrypted={ %s }\n"), (LPCTSTR)DebugByteArray(vntDecrypted));
|
|
|
|
// extract encryption key bytes
|
|
|
|
_variant_t vntBytes;
|
|
CreateByteArray(ENCRYPTION_KEY_SIZE, vntBytes);
|
|
memcpy(vntBytes.parray->pvData, (BYTE*)vntDecrypted.parray->pvData, ENCRYPTION_KEY_SIZE);
|
|
|
|
Trace(_T(" vntBytes={ %s }\r\n"), (LPCTSTR)DebugByteArray(vntBytes));
|
|
|
|
// extract hash of encryption key bytes
|
|
|
|
_variant_t vntHashValue;
|
|
DWORD cbHashValue = vntDecrypted.parray->rgsabound[0].cElements - ENCRYPTION_KEY_SIZE;
|
|
CreateByteArray(cbHashValue, vntHashValue);
|
|
memcpy(vntHashValue.parray->pvData, (BYTE*)vntDecrypted.parray->pvData + ENCRYPTION_KEY_SIZE, cbHashValue);
|
|
|
|
// Trace(_T(" vntHashValue={ %s }\n"), (LPCTSTR)DebugByteArray(vntHashValue));
|
|
|
|
// create hash from bytes and create hash from hash value
|
|
|
|
CCryptHash hashA(CreateHash(CALG_SHA1));
|
|
hashA.Hash(vntBytes);
|
|
|
|
CCryptHash hashB(CreateHash(CALG_SHA1));
|
|
hashB.SetValue(vntHashValue);
|
|
|
|
// if hashes compare store encryption key bytes
|
|
|
|
if (hashA == hashB)
|
|
{
|
|
StoreBytes(m_szIdPrefix, vntBytes);
|
|
}
|
|
else
|
|
{
|
|
_com_issue_error(HRESULT_FROM_WIN32(ERROR_INVALID_PASSWORD));
|
|
}
|
|
|
|
SecureZeroMemory(GET_BYTE_ARRAY_DATA(vntDecrypted), GET_BYTE_ARRAY_SIZE(vntDecrypted));
|
|
SecureZeroMemory(GET_BYTE_ARRAY_DATA(vntBytes), GET_BYTE_ARRAY_SIZE(vntBytes));
|
|
SecureZeroMemory(GET_BYTE_ARRAY_DATA(vntHashValue), GET_BYTE_ARRAY_SIZE(vntHashValue));
|
|
}
|
|
|
|
|
|
// ImportSessionKey Method
|
|
|
|
void CSourceCrypt::ImportSessionKey(const _variant_t& vntEncryptedKey)
|
|
{
|
|
Trace(_T("ImportSessionKey(vntEncryptedKey={ %s })\r\n"), (LPCTSTR)DebugByteArray(vntEncryptedKey));
|
|
|
|
// validate parameters
|
|
|
|
if ((vntEncryptedKey.vt != (VT_UI1|VT_ARRAY)) || ((vntEncryptedKey.parray == NULL)))
|
|
{
|
|
_com_issue_error(E_INVALIDARG);
|
|
}
|
|
|
|
// get encryption key
|
|
|
|
CCryptKey keyEncryption(GetEncryptionKey(m_szIdPrefix));
|
|
|
|
// decrypt session key bytes plus hash
|
|
|
|
_variant_t vntDecrypted = keyEncryption.Decrypt(NULL, true, vntEncryptedKey);
|
|
|
|
// extract session key bytes
|
|
|
|
_variant_t vntBytes;
|
|
CreateByteArray(SESSION_KEY_SIZE, vntBytes);
|
|
memcpy(vntBytes.parray->pvData, vntDecrypted.parray->pvData, SESSION_KEY_SIZE);
|
|
|
|
// extract hash of session key bytes
|
|
|
|
_variant_t vntHashValue;
|
|
DWORD cbHashValue = vntDecrypted.parray->rgsabound[0].cElements - SESSION_KEY_SIZE;
|
|
CreateByteArray(cbHashValue, vntHashValue);
|
|
memcpy(vntHashValue.parray->pvData, (BYTE*)vntDecrypted.parray->pvData + SESSION_KEY_SIZE, cbHashValue);
|
|
|
|
// create hash from bytes and create hash from hash value
|
|
|
|
CCryptHash hashA(CreateHash(CALG_SHA1));
|
|
hashA.Hash(vntBytes);
|
|
|
|
CCryptHash hashB(CreateHash(CALG_SHA1));
|
|
hashB.SetValue(vntHashValue);
|
|
|
|
// if hashes compare
|
|
|
|
if (hashA == hashB)
|
|
{
|
|
// derive session key from session key bytes hash
|
|
|
|
m_keySession.Attach(DeriveKey(CALG_3DES, hashA));
|
|
}
|
|
else
|
|
{
|
|
_com_issue_error(E_FAIL);
|
|
}
|
|
|
|
SecureZeroMemory(GET_BYTE_ARRAY_DATA(vntDecrypted), GET_BYTE_ARRAY_SIZE(vntDecrypted));
|
|
SecureZeroMemory(GET_BYTE_ARRAY_DATA(vntBytes), GET_BYTE_ARRAY_SIZE(vntBytes));
|
|
SecureZeroMemory(GET_BYTE_ARRAY_DATA(vntHashValue), GET_BYTE_ARRAY_SIZE(vntHashValue));
|
|
}
|
|
|
|
|
|
// Decrypt Method
|
|
|
|
_bstr_t CSourceCrypt::Decrypt(const _variant_t& vntData)
|
|
{
|
|
Trace(_T("Decrypt(vntData={ %s })\r\n"), (LPCTSTR)DebugByteArray(vntData));
|
|
|
|
// decrypt data
|
|
|
|
_variant_t vnt = m_keySession.Decrypt(NULL, true, vntData);
|
|
|
|
// convert into string
|
|
|
|
BSTR bstr;
|
|
|
|
HRESULT hr = BstrFromVector(vnt.parray, &bstr);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
_com_issue_error(hr);
|
|
}
|
|
|
|
SecureZeroMemory(GET_BYTE_ARRAY_DATA(vnt), GET_BYTE_ARRAY_SIZE(vnt));
|
|
|
|
return bstr;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Domain Crypt Class
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
// Constructor
|
|
|
|
CDomainCrypt::CDomainCrypt()
|
|
{
|
|
Trace(_T("CDomainCrypt::CDomainCrypt()\r\n"));
|
|
}
|
|
|
|
|
|
// Destructor
|
|
|
|
CDomainCrypt::~CDomainCrypt()
|
|
{
|
|
Trace(_T("CDomainCrypt::~CDomainCrypt()\r\n"));
|
|
}
|
|
|
|
|
|
// GetEncryptionKey Method
|
|
|
|
HCRYPTKEY CDomainCrypt::GetEncryptionKey(LPCTSTR pszKeyId)
|
|
{
|
|
// retrieve bytes
|
|
|
|
_variant_t vntBytes = RetrieveBytes(pszKeyId);
|
|
|
|
// set hash value
|
|
|
|
CCryptHash hash;
|
|
hash.Attach(CreateHash(CALG_SHA1));
|
|
hash.Hash(vntBytes);
|
|
|
|
// create encryption key derived from bytes
|
|
|
|
SecureZeroMemory(GET_BYTE_ARRAY_DATA(vntBytes), GET_BYTE_ARRAY_SIZE(vntBytes));
|
|
|
|
return DeriveKey(CALG_3DES, hash);
|
|
}
|
|
|
|
|
|
// StoreBytes Method
|
|
|
|
void CDomainCrypt::StoreBytes(LPCTSTR pszId, const _variant_t& vntBytes)
|
|
{
|
|
// validate parameters
|
|
|
|
if ((pszId == NULL) || (pszId[0] == NULL))
|
|
{
|
|
_com_issue_error(E_INVALIDARG);
|
|
}
|
|
|
|
if ((vntBytes.vt != VT_EMPTY) && (vntBytes.vt != (VT_UI1|VT_ARRAY)))
|
|
{
|
|
_com_issue_error(E_INVALIDARG);
|
|
}
|
|
|
|
if ((vntBytes.vt == (VT_UI1|VT_ARRAY)) && (vntBytes.parray == NULL))
|
|
{
|
|
_com_issue_error(E_INVALIDARG);
|
|
}
|
|
|
|
LSA_HANDLE hPolicy = NULL;
|
|
|
|
try
|
|
{
|
|
// open policy object
|
|
|
|
LSA_OBJECT_ATTRIBUTES loa = { sizeof(LSA_OBJECT_ATTRIBUTES), NULL, NULL, 0, NULL, NULL };
|
|
|
|
NTSTATUS ntsStatus = LsaOpenPolicy(NULL, &loa, POLICY_CREATE_SECRET, &hPolicy);
|
|
|
|
if (!LSA_SUCCESS(ntsStatus))
|
|
{
|
|
_com_issue_error(HRESULT_FROM_WIN32(LsaNtStatusToWinError(ntsStatus)));
|
|
}
|
|
|
|
// store data
|
|
|
|
PWSTR pwsKey = const_cast<PWSTR>(pszId);
|
|
USHORT cbKey = _tcslen(pszId) * sizeof(_TCHAR);
|
|
|
|
PWSTR pwsData = NULL;
|
|
USHORT cbData = 0;
|
|
|
|
if (vntBytes.vt != VT_EMPTY)
|
|
{
|
|
pwsData = reinterpret_cast<PWSTR>(vntBytes.parray->pvData);
|
|
cbData = (USHORT) vntBytes.parray->rgsabound[0].cElements;
|
|
}
|
|
|
|
LSA_UNICODE_STRING lusKey = { cbKey, cbKey, pwsKey };
|
|
LSA_UNICODE_STRING lusData = { cbData, cbData, pwsData };
|
|
|
|
ntsStatus = LsaStorePrivateData(hPolicy, &lusKey, &lusData);
|
|
|
|
if (!LSA_SUCCESS(ntsStatus))
|
|
{
|
|
_com_issue_error(HRESULT_FROM_WIN32(LsaNtStatusToWinError(ntsStatus)));
|
|
}
|
|
|
|
// close policy object
|
|
|
|
LsaClose(hPolicy);
|
|
}
|
|
catch (...)
|
|
{
|
|
if (hPolicy)
|
|
{
|
|
LsaClose(hPolicy);
|
|
}
|
|
|
|
throw;
|
|
}
|
|
}
|
|
|
|
|
|
// RetrievePrivateData Method
|
|
|
|
_variant_t CDomainCrypt::RetrieveBytes(LPCTSTR pszId)
|
|
{
|
|
_variant_t vntBytes;
|
|
|
|
// validate parameters
|
|
|
|
if ((pszId == NULL) || (pszId[0] == NULL))
|
|
{
|
|
_com_issue_error(E_INVALIDARG);
|
|
}
|
|
|
|
LSA_HANDLE hPolicy = NULL;
|
|
|
|
try
|
|
{
|
|
// open policy object
|
|
|
|
LSA_OBJECT_ATTRIBUTES loa = { sizeof(LSA_OBJECT_ATTRIBUTES), NULL, NULL, 0, NULL, NULL };
|
|
|
|
NTSTATUS ntsStatus = LsaOpenPolicy(NULL, &loa, POLICY_GET_PRIVATE_INFORMATION, &hPolicy);
|
|
|
|
if (!LSA_SUCCESS(ntsStatus))
|
|
{
|
|
_com_issue_error(HRESULT_FROM_WIN32(LsaNtStatusToWinError(ntsStatus)));
|
|
}
|
|
|
|
// retrieve data
|
|
|
|
PWSTR pwsKey = const_cast<PWSTR>(pszId);
|
|
USHORT cbKey = _tcslen(pszId) * sizeof(_TCHAR);
|
|
|
|
LSA_UNICODE_STRING lusKey = { cbKey, cbKey, pwsKey };
|
|
PLSA_UNICODE_STRING plusData;
|
|
|
|
ntsStatus = LsaRetrievePrivateData(hPolicy, &lusKey, &plusData);
|
|
|
|
if (!LSA_SUCCESS(ntsStatus))
|
|
{
|
|
_com_issue_error(HRESULT_FROM_WIN32(LsaNtStatusToWinError(ntsStatus)));
|
|
}
|
|
|
|
vntBytes.parray = SafeArrayCreateVector(VT_UI1, 0, plusData->Length);
|
|
|
|
if (vntBytes.parray == NULL)
|
|
{
|
|
LsaFreeMemory(plusData);
|
|
_com_issue_error(E_OUTOFMEMORY);
|
|
}
|
|
|
|
vntBytes.vt = VT_UI1|VT_ARRAY;
|
|
|
|
memcpy(vntBytes.parray->pvData, plusData->Buffer, plusData->Length);
|
|
|
|
LsaFreeMemory(plusData);
|
|
|
|
// close policy object
|
|
|
|
LsaClose(hPolicy);
|
|
}
|
|
catch (...)
|
|
{
|
|
if (hPolicy)
|
|
{
|
|
LsaClose(hPolicy);
|
|
}
|
|
|
|
throw;
|
|
}
|
|
|
|
return vntBytes;
|
|
}
|
|
|
|
|
|
// private data key identifier
|
|
|
|
_TCHAR CDomainCrypt::m_szIdPrefix[] = _T("L$6A2899C0-CECE-459A-B5EB-7ED04DE61388");
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Crypt Provider Class
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
// Constructors
|
|
//
|
|
// Notes:
|
|
// If the enhanced provider is not installed, CryptAcquireContext() generates
|
|
// the following error: (0x80090019) The keyset is not defined.
|
|
|
|
CCryptProvider::CCryptProvider() :
|
|
m_hProvider(NULL)
|
|
{
|
|
Trace(_T("E CCryptProvider::CCryptProvider(this=0x%p)\r\n"), this);
|
|
|
|
if (!CryptAcquireContext(&m_hProvider, NULL, MS_ENHANCED_PROV, PROV_RSA_FULL, CRYPT_MACHINE_KEYSET|CRYPT_VERIFYCONTEXT))
|
|
{
|
|
_com_issue_error(HRESULT_FROM_WIN32(GetLastError()));
|
|
}
|
|
|
|
#ifdef _DEBUG
|
|
char szProvider[256];
|
|
DWORD cbProvider = sizeof(szProvider);
|
|
|
|
if (CryptGetProvParam(m_hProvider, PP_NAME, (BYTE*) szProvider, &cbProvider, 0))
|
|
{
|
|
}
|
|
|
|
DWORD dwVersion;
|
|
DWORD cbVersion = sizeof(dwVersion);
|
|
|
|
if (CryptGetProvParam(m_hProvider, PP_VERSION, (BYTE*) &dwVersion, &cbVersion, 0))
|
|
{
|
|
}
|
|
|
|
// char szContainer[256];
|
|
// DWORD cbContainer = sizeof(szContainer);
|
|
|
|
// if (CryptGetProvParam(m_hProvider, PP_CONTAINER, (BYTE*) szContainer, &cbContainer, 0))
|
|
// {
|
|
// }
|
|
#endif
|
|
|
|
Trace(_T("L CCryptProvider::CCryptProvider()\r\n"));
|
|
}
|
|
|
|
CCryptProvider::CCryptProvider(const CCryptProvider& r) :
|
|
m_hProvider(r.m_hProvider)
|
|
{
|
|
// if (!CryptContextAddRef(r.m_hProvider, NULL, 0))
|
|
// {
|
|
// _com_issue_error(HRESULT_FROM_WIN32(GetLastError()));
|
|
// }
|
|
}
|
|
|
|
|
|
// Destructor
|
|
|
|
CCryptProvider::~CCryptProvider()
|
|
{
|
|
Trace(_T("E CCryptProvider::~CCryptProvider()\r\n"));
|
|
|
|
if (m_hProvider)
|
|
{
|
|
if (!CryptReleaseContext(m_hProvider, 0))
|
|
{
|
|
#ifdef _DEBUG
|
|
DebugBreak();
|
|
#endif
|
|
}
|
|
}
|
|
|
|
Trace(_T("L CCryptProvider::~CCryptProvider()\r\n"));
|
|
}
|
|
|
|
|
|
// assignment operators
|
|
|
|
CCryptProvider& CCryptProvider::operator =(const CCryptProvider& r)
|
|
{
|
|
m_hProvider = r.m_hProvider;
|
|
|
|
// if (!CryptContextAddRef(r.m_hProvider, NULL, 0))
|
|
// {
|
|
// _com_issue_error(HRESULT_FROM_WIN32(GetLastError()));
|
|
// }
|
|
|
|
return *this;
|
|
}
|
|
|
|
|
|
// CreateHash Method
|
|
|
|
HCRYPTHASH CCryptProvider::CreateHash(ALG_ID aid)
|
|
{
|
|
HCRYPTHASH hHash;
|
|
|
|
if (!CryptCreateHash(m_hProvider, aid, 0, 0, &hHash))
|
|
{
|
|
_com_issue_error(HRESULT_FROM_WIN32(GetLastError()));
|
|
}
|
|
|
|
return hHash;
|
|
}
|
|
|
|
|
|
// DeriveKey Method
|
|
|
|
HCRYPTKEY CCryptProvider::DeriveKey(ALG_ID aid, HCRYPTHASH hHash, DWORD dwFlags)
|
|
{
|
|
HCRYPTKEY hKey;
|
|
|
|
if (!CryptDeriveKey(m_hProvider, aid, hHash, dwFlags, &hKey))
|
|
{
|
|
_com_issue_error(HRESULT_FROM_WIN32(GetLastError()));
|
|
}
|
|
|
|
return hKey;
|
|
}
|
|
|
|
|
|
// GenerateRandom Method
|
|
//
|
|
// Generates a specified number of random bytes.
|
|
|
|
_variant_t CCryptProvider::GenerateRandom(DWORD dwNumberOfBytes) const
|
|
{
|
|
_variant_t vntRandom;
|
|
|
|
// create byte array of specified length
|
|
|
|
vntRandom.parray = SafeArrayCreateVector(VT_UI1, 0, dwNumberOfBytes);
|
|
|
|
if (vntRandom.parray == NULL)
|
|
{
|
|
_com_issue_error(E_OUTOFMEMORY);
|
|
}
|
|
|
|
vntRandom.vt = VT_UI1|VT_ARRAY;
|
|
|
|
// generate specified number of random bytes
|
|
|
|
GenerateRandom((BYTE*)vntRandom.parray->pvData, dwNumberOfBytes);
|
|
|
|
return vntRandom;
|
|
}
|
|
|
|
|
|
// GenerateRandom Method
|
|
//
|
|
// Generates a specified number of random bytes.
|
|
|
|
void CCryptProvider::GenerateRandom(BYTE* pbData, DWORD cbData) const
|
|
{
|
|
// generate specified number of random bytes
|
|
|
|
if (!CryptGenRandom(m_hProvider, cbData, pbData))
|
|
{
|
|
_com_issue_error(HRESULT_FROM_WIN32(GetLastError()));
|
|
}
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Crypt Key Class
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
// Constructor
|
|
|
|
CCryptKey::CCryptKey(HCRYPTKEY hKey) :
|
|
m_hKey(hKey)
|
|
{
|
|
}
|
|
|
|
|
|
// Destructor
|
|
|
|
CCryptKey::~CCryptKey()
|
|
{
|
|
if (m_hKey)
|
|
{
|
|
if (!CryptDestroyKey(m_hKey))
|
|
{
|
|
_com_issue_error(HRESULT_FROM_WIN32(GetLastError()));
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// Encrypt Method
|
|
|
|
_variant_t CCryptKey::Encrypt(HCRYPTHASH hHash, bool bFinal, const _variant_t& vntData)
|
|
{
|
|
_variant_t vntEncrypted;
|
|
|
|
// validate parameters
|
|
|
|
if ((vntData.vt != (VT_UI1|VT_ARRAY)) || ((vntData.parray == NULL)))
|
|
{
|
|
_com_issue_error(E_INVALIDARG);
|
|
}
|
|
|
|
// get encrypted data size
|
|
|
|
DWORD cbData = vntData.parray->rgsabound[0].cElements;
|
|
DWORD cbBuffer = cbData;
|
|
|
|
if (!CryptEncrypt(m_hKey, hHash, bFinal ? TRUE : FALSE, 0, NULL, &cbBuffer, 0))
|
|
{
|
|
_com_issue_error(HRESULT_FROM_WIN32(GetLastError()));
|
|
}
|
|
|
|
// create encrypted data buffer
|
|
|
|
vntEncrypted.parray = SafeArrayCreateVector(VT_UI1, 0, cbBuffer);
|
|
|
|
if (vntEncrypted.parray == NULL)
|
|
{
|
|
_com_issue_error(E_OUTOFMEMORY);
|
|
}
|
|
|
|
vntEncrypted.vt = VT_UI1|VT_ARRAY;
|
|
|
|
// copy data to encrypted buffer
|
|
|
|
memcpy(vntEncrypted.parray->pvData, vntData.parray->pvData, cbData);
|
|
|
|
// encrypt data
|
|
|
|
BYTE* pbData = (BYTE*) vntEncrypted.parray->pvData;
|
|
|
|
if (!CryptEncrypt(m_hKey, hHash, bFinal ? TRUE : FALSE, 0, pbData, &cbData, cbBuffer))
|
|
{
|
|
_com_issue_error(HRESULT_FROM_WIN32(GetLastError()));
|
|
}
|
|
|
|
return vntEncrypted;
|
|
}
|
|
|
|
|
|
// Decrypt Method
|
|
|
|
_variant_t CCryptKey::Decrypt(HCRYPTHASH hHash, bool bFinal, const _variant_t& vntData)
|
|
{
|
|
_variant_t vntDecrypted;
|
|
|
|
// validate parameters
|
|
|
|
if ((vntData.vt != (VT_UI1|VT_ARRAY)) || ((vntData.parray == NULL)))
|
|
{
|
|
_com_issue_error(E_INVALIDARG);
|
|
}
|
|
|
|
// decrypt data
|
|
|
|
_variant_t vnt = vntData;
|
|
|
|
BYTE* pb = (BYTE*) vnt.parray->pvData;
|
|
DWORD cb = vnt.parray->rgsabound[0].cElements;
|
|
|
|
if (!CryptDecrypt(m_hKey, hHash, bFinal ? TRUE : FALSE, 0, pb, &cb))
|
|
{
|
|
_com_issue_error(HRESULT_FROM_WIN32(GetLastError()));
|
|
}
|
|
|
|
// 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)
|
|
{
|
|
_com_issue_error(E_OUTOFMEMORY);
|
|
}
|
|
|
|
vntDecrypted.vt = VT_UI1|VT_ARRAY;
|
|
|
|
memcpy(vntDecrypted.parray->pvData, vnt.parray->pvData, cb);
|
|
|
|
SecureZeroMemory(GET_BYTE_ARRAY_DATA(vnt), GET_BYTE_ARRAY_SIZE(vnt));
|
|
|
|
return vntDecrypted;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Crypt Hash Class
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
// Constructor
|
|
|
|
CCryptHash::CCryptHash(HCRYPTHASH hHash) :
|
|
m_hHash(hHash)
|
|
{
|
|
}
|
|
|
|
|
|
// Destructor
|
|
|
|
CCryptHash::~CCryptHash()
|
|
{
|
|
if (m_hHash)
|
|
{
|
|
if (!CryptDestroyHash(m_hHash))
|
|
{
|
|
_com_issue_error(HRESULT_FROM_WIN32(GetLastError()));
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// GetValue Method
|
|
|
|
_variant_t CCryptHash::GetValue() const
|
|
{
|
|
_variant_t vntValue;
|
|
|
|
// get hash size
|
|
|
|
DWORD dwHashSize;
|
|
DWORD cbHashSize = sizeof(DWORD);
|
|
|
|
if (!CryptGetHashParam(m_hHash, HP_HASHSIZE, (BYTE*)&dwHashSize, &cbHashSize, 0))
|
|
{
|
|
_com_issue_error(HRESULT_FROM_WIN32(GetLastError()));
|
|
}
|
|
|
|
// allocate buffer
|
|
|
|
vntValue.parray = SafeArrayCreateVector(VT_UI1, 0, dwHashSize);
|
|
|
|
if (vntValue.parray == NULL)
|
|
{
|
|
_com_issue_error(E_OUTOFMEMORY);
|
|
}
|
|
|
|
vntValue.vt = VT_UI1|VT_ARRAY;
|
|
|
|
// get hash value
|
|
|
|
if (!CryptGetHashParam(m_hHash, HP_HASHVAL, (BYTE*)vntValue.parray->pvData, &dwHashSize, 0))
|
|
{
|
|
_com_issue_error(HRESULT_FROM_WIN32(GetLastError()));
|
|
}
|
|
|
|
return vntValue;
|
|
}
|
|
|
|
|
|
// SetValue Method
|
|
|
|
void CCryptHash::SetValue(const _variant_t& vntValue)
|
|
{
|
|
// if parameter is valid
|
|
|
|
if ((vntValue.vt == (VT_UI1|VT_ARRAY)) && ((vntValue.parray != NULL)))
|
|
{
|
|
// get hash size
|
|
|
|
DWORD dwHashSize;
|
|
DWORD cbHashSize = sizeof(DWORD);
|
|
|
|
if (!CryptGetHashParam(m_hHash, HP_HASHSIZE, (BYTE*)&dwHashSize, &cbHashSize, 0))
|
|
{
|
|
_com_issue_error(HRESULT_FROM_WIN32(GetLastError()));
|
|
}
|
|
|
|
// validate hash size
|
|
|
|
BYTE* pbValue = (BYTE*)vntValue.parray->pvData;
|
|
DWORD cbValue = vntValue.parray->rgsabound[0].cElements;
|
|
|
|
if (cbValue != dwHashSize)
|
|
{
|
|
_com_issue_error(E_INVALIDARG);
|
|
}
|
|
|
|
// set hash value
|
|
|
|
if (!CryptSetHashParam(m_hHash, HP_HASHVAL, (BYTE*)pbValue, 0))
|
|
{
|
|
_com_issue_error(HRESULT_FROM_WIN32(GetLastError()));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
_com_issue_error(E_INVALIDARG);
|
|
}
|
|
}
|
|
|
|
|
|
// Hash Method
|
|
|
|
void CCryptHash::Hash(LPCTSTR pszData)
|
|
{
|
|
if (pszData && pszData[0])
|
|
{
|
|
Hash((BYTE*)pszData, _tcslen(pszData) * sizeof(_TCHAR));
|
|
}
|
|
else
|
|
{
|
|
_com_issue_error(E_INVALIDARG);
|
|
}
|
|
}
|
|
|
|
|
|
// Hash Method
|
|
|
|
void CCryptHash::Hash(const _variant_t& vntData)
|
|
{
|
|
if ((vntData.vt == (VT_UI1|VT_ARRAY)) && ((vntData.parray != NULL)))
|
|
{
|
|
Hash((BYTE*)vntData.parray->pvData, vntData.parray->rgsabound[0].cElements);
|
|
}
|
|
else
|
|
{
|
|
_com_issue_error(E_INVALIDARG);
|
|
}
|
|
}
|
|
|
|
|
|
// Hash Method
|
|
|
|
void CCryptHash::Hash(BYTE* pbData, DWORD cbData)
|
|
{
|
|
if ((pbData != NULL) && (cbData > 0))
|
|
{
|
|
if (!CryptHashData(m_hHash, pbData, cbData, 0))
|
|
{
|
|
_com_issue_error(HRESULT_FROM_WIN32(GetLastError()));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
_com_issue_error(E_INVALIDARG);
|
|
}
|
|
}
|
|
|
|
|
|
bool CCryptHash::operator ==(const CCryptHash& hash)
|
|
{
|
|
bool bEqual = false;
|
|
|
|
DWORD cbSize = sizeof(DWORD);
|
|
|
|
// compare hash sizes
|
|
|
|
DWORD dwSizeA;
|
|
DWORD dwSizeB;
|
|
|
|
if (!CryptGetHashParam(m_hHash, HP_HASHSIZE, (BYTE*)&dwSizeA, &cbSize, 0))
|
|
{
|
|
_com_issue_error(HRESULT_FROM_WIN32(GetLastError()));
|
|
}
|
|
|
|
if (!CryptGetHashParam(hash.m_hHash, HP_HASHSIZE, (BYTE*)&dwSizeB, &cbSize, 0))
|
|
{
|
|
_com_issue_error(HRESULT_FROM_WIN32(GetLastError()));
|
|
}
|
|
|
|
// if sizes are equal
|
|
|
|
if (dwSizeA == dwSizeB)
|
|
{
|
|
// compare hashes
|
|
|
|
c_array<BYTE> pbA(dwSizeA);
|
|
c_array<BYTE> pbB(dwSizeB);
|
|
|
|
if (!CryptGetHashParam(m_hHash, HP_HASHVAL, pbA, &dwSizeA, 0))
|
|
{
|
|
_com_issue_error(HRESULT_FROM_WIN32(GetLastError()));
|
|
}
|
|
|
|
if (!CryptGetHashParam(hash.m_hHash, HP_HASHVAL, pbB, &dwSizeB, 0))
|
|
{
|
|
_com_issue_error(HRESULT_FROM_WIN32(GetLastError()));
|
|
}
|
|
|
|
if (memcmp(pbA, pbB, dwSizeA) == 0)
|
|
{
|
|
bEqual = true;
|
|
}
|
|
}
|
|
|
|
return bEqual;
|
|
}
|