295 lines
11 KiB
C
295 lines
11 KiB
C
/* Benjamin DELPY `gentilkiwi`
|
|
http://blog.gentilkiwi.com
|
|
benjamin@gentilkiwi.com
|
|
Licence : https://creativecommons.org/licenses/by/4.0/
|
|
*/
|
|
#include "kull_m_crypto_ngc.h"
|
|
|
|
BOOL kull_m_crypto_ngc_keyvalue_derived_software(PBYTE pbLabel, DWORD cbLabel, PBYTE pbContext, DWORD cbContext, LPCBYTE Key, DWORD cbKey, PBYTE DerivedKey, DWORD cbDerivedKey)
|
|
{
|
|
BOOL status = FALSE;
|
|
NTSTATUS bStatus;
|
|
BCRYPT_ALG_HANDLE hAlgSP800108;
|
|
BCRYPT_KEY_HANDLE hKeySP800108;
|
|
DWORD ObjectLengthSP800108, cbResult;
|
|
PUCHAR pbKeyObjectSP800108;
|
|
BCryptBuffer buffer[] = {
|
|
{cbLabel, KDF_LABEL, pbLabel},
|
|
{cbContext, KDF_CONTEXT, pbContext},
|
|
{sizeof(BCRYPT_SHA256_ALGORITHM), KDF_HASH_ALGORITHM, BCRYPT_SHA256_ALGORITHM},
|
|
};
|
|
BCryptBufferDesc bufferDesc = {BCRYPTBUFFER_VERSION, ARRAYSIZE(buffer), buffer};
|
|
|
|
__try
|
|
{
|
|
bStatus = BCryptOpenAlgorithmProvider(&hAlgSP800108, BCRYPT_SP800108_CTR_HMAC_ALGORITHM, NULL, 0);
|
|
if(BCRYPT_SUCCESS(bStatus))
|
|
{
|
|
bStatus = BCryptGetProperty(hAlgSP800108, BCRYPT_OBJECT_LENGTH, (PUCHAR) &ObjectLengthSP800108, sizeof(ObjectLengthSP800108), &cbResult, 0);
|
|
if(BCRYPT_SUCCESS(bStatus))
|
|
{
|
|
if(pbKeyObjectSP800108 = (PUCHAR) LocalAlloc(LPTR, ObjectLengthSP800108))
|
|
{
|
|
bStatus = BCryptGenerateSymmetricKey(hAlgSP800108, &hKeySP800108, pbKeyObjectSP800108, ObjectLengthSP800108, (PUCHAR) Key, cbKey, 0);
|
|
if(BCRYPT_SUCCESS(bStatus))
|
|
{
|
|
bStatus = BCryptKeyDerivation(hKeySP800108, &bufferDesc, DerivedKey, cbDerivedKey, &cbResult, 0);
|
|
if(BCRYPT_SUCCESS(bStatus))
|
|
{
|
|
status = (cbResult == cbDerivedKey);
|
|
if(!status)
|
|
PRINT_ERROR(L"Bad cbResult (%u vs %u)\n", cbResult, cbDerivedKey);
|
|
}
|
|
else PRINT_ERROR(L"BCryptKeyDerivation: 0x%08x\n", bStatus);
|
|
BCryptDestroyKey(hKeySP800108);
|
|
}
|
|
else PRINT_ERROR(L"BCryptGenerateSymmetricKey: 0x%08x\n", bStatus);
|
|
LocalFree(pbKeyObjectSP800108);
|
|
}
|
|
}
|
|
else PRINT_ERROR(L"BCryptGetProperty: 0x%08x\n", bStatus);
|
|
BCryptCloseAlgorithmProvider(hAlgSP800108, 0);
|
|
}
|
|
else PRINT_ERROR(L"BCryptOpenAlgorithmProvider: 0x%08x\n", bStatus);
|
|
}
|
|
__except(GetExceptionCode() == ERROR_DLL_NOT_FOUND)
|
|
{
|
|
PRINT_ERROR(L"No CNG?\n");
|
|
}
|
|
return status;
|
|
}
|
|
|
|
BOOL kull_m_crypto_ngc_keyvalue_derived_hardware(PBYTE pbLabel, DWORD cbLabel, PBYTE pbContext, DWORD cbContext, LPCWSTR TransportKeyName, LPCBYTE Key, DWORD cbKey, PBYTE DerivedKey, DWORD cbDerivedKey)
|
|
{
|
|
BOOL status = FALSE;
|
|
SECURITY_STATUS nStatus;
|
|
NCRYPT_PROV_HANDLE hProvider;
|
|
NCRYPT_KEY_HANDLE hImportKey, hKey;
|
|
DWORD cbResult;
|
|
NCryptBuffer buffer[] = {
|
|
{cbLabel, KDF_LABEL, pbLabel},
|
|
{cbContext, KDF_CONTEXT, pbContext},
|
|
{sizeof(NCRYPT_SHA256_ALGORITHM), KDF_HASH_ALGORITHM, NCRYPT_SHA256_ALGORITHM},
|
|
};
|
|
NCryptBufferDesc bufferDesc = {NCRYPTBUFFER_VERSION, ARRAYSIZE(buffer), buffer};
|
|
PNCRYPTKEYDERIVATION NCryptKeyDerivation; // tofix
|
|
|
|
__try
|
|
{
|
|
nStatus = NCryptOpenStorageProvider(&hProvider, MS_PLATFORM_CRYPTO_PROVIDER, 0);
|
|
if(nStatus == ERROR_SUCCESS)
|
|
{
|
|
nStatus = NCryptOpenKey(hProvider, &hImportKey, TransportKeyName, 0, 0);
|
|
if(nStatus == ERROR_SUCCESS)
|
|
{
|
|
nStatus = NCryptImportKey(hProvider, hImportKey, NCRYPT_OPAQUETRANSPORT_BLOB, NULL, &hKey, (PBYTE) Key, cbKey, 0);
|
|
if(nStatus == ERROR_SUCCESS)
|
|
{
|
|
NCryptKeyDerivation = (PNCRYPTKEYDERIVATION) GetProcAddress(GetModuleHandle(L"ncrypt.dll"), "NCryptKeyDerivation"); // tofix
|
|
if(NCryptKeyDerivation)
|
|
{
|
|
nStatus = NCryptKeyDerivation(hKey, &bufferDesc, DerivedKey, cbDerivedKey, &cbResult, 0);
|
|
if(nStatus == ERROR_SUCCESS)
|
|
{
|
|
status = (cbResult == cbDerivedKey);
|
|
if(!status)
|
|
PRINT_ERROR(L"Bad cbResult (%u vs %u)\n", cbResult, cbDerivedKey);
|
|
}
|
|
else PRINT_ERROR(L"NCryptKeyDerivation: 0x%08x\n", nStatus);
|
|
}
|
|
else PRINT_ERROR(L"No NCryptKeyDerivation?\n", nStatus);
|
|
NCryptFreeObject(hKey);
|
|
}
|
|
else PRINT_ERROR(L"NCryptImportKey: 0x%08x\n", nStatus);
|
|
NCryptFreeObject(hImportKey);
|
|
}
|
|
else PRINT_ERROR(L"NCryptOpenKey: 0x%08x\n", nStatus);
|
|
NCryptFreeObject(hProvider);
|
|
}
|
|
else PRINT_ERROR(L"NCryptOpenStorageProvider: 0x%08x\n", nStatus);
|
|
}
|
|
__except(GetExceptionCode() == ERROR_DLL_NOT_FOUND)
|
|
{
|
|
PRINT_ERROR(L"No CNG?\n");
|
|
}
|
|
return status;
|
|
}
|
|
|
|
BOOL kull_m_crypto_ngc_signature_derived(LPCBYTE pcbKey, DWORD cbKey, LPCBYTE pcbData, DWORD cbData, LPBYTE pbHash, DWORD cbHash)
|
|
{
|
|
BOOL status = FALSE;
|
|
NTSTATUS ntStatus;
|
|
BCRYPT_ALG_HANDLE hAlgorithm;
|
|
BCRYPT_HASH_HANDLE hHash;
|
|
DWORD ObjectLength, cbResult;
|
|
PUCHAR pbHashObject;
|
|
|
|
__try
|
|
{
|
|
ntStatus = BCryptOpenAlgorithmProvider(&hAlgorithm, BCRYPT_SHA256_ALGORITHM, MS_PRIMITIVE_PROVIDER, BCRYPT_ALG_HANDLE_HMAC_FLAG);
|
|
if(BCRYPT_SUCCESS(ntStatus))
|
|
{
|
|
ntStatus = BCryptGetProperty(hAlgorithm, BCRYPT_OBJECT_LENGTH, (PUCHAR) &ObjectLength, sizeof(ObjectLength), &cbResult, 0);
|
|
if(BCRYPT_SUCCESS(ntStatus))
|
|
{
|
|
if(pbHashObject = (PUCHAR) LocalAlloc(LPTR, ObjectLength))
|
|
{
|
|
ntStatus = BCryptCreateHash(hAlgorithm, &hHash, pbHashObject, ObjectLength, (PUCHAR) pcbKey, cbKey, 0);
|
|
if(BCRYPT_SUCCESS(ntStatus))
|
|
{
|
|
BCryptHashData(hHash, (PUCHAR) pcbData, cbData, 0);
|
|
ntStatus = BCryptFinishHash(hHash, pbHash, cbHash, 0);
|
|
status = BCRYPT_SUCCESS(ntStatus);
|
|
if(!status)
|
|
PRINT_ERROR(L"BCryptFinishHash: 0x%08x\n", ntStatus);
|
|
BCryptDestroyHash(hHash);
|
|
}
|
|
else PRINT_ERROR(L"BCryptCreateHash: 0x%08x\n", ntStatus);
|
|
LocalFree(pbHashObject);
|
|
}
|
|
}
|
|
else PRINT_ERROR(L"BCryptGetProperty: 0x%08x\n", ntStatus);
|
|
BCryptCloseAlgorithmProvider(hAlgorithm, 0);
|
|
}
|
|
else PRINT_ERROR(L"BCryptOpenAlgorithmProvider: 0x%08x\n", ntStatus);
|
|
}
|
|
__except(GetExceptionCode() == ERROR_DLL_NOT_FOUND)
|
|
{
|
|
PRINT_ERROR(L"No CNG?\n");
|
|
}
|
|
return status;
|
|
}
|
|
|
|
BOOL kull_m_crypto_ngc_signature_pop(PBYTE pbKey, DWORD cbKey, PBYTE pbLabel, DWORD cbLabel, PBYTE pbContext, DWORD cbContext, PBYTE pbData, DWORD cbData, PBYTE *ppbOutput, PDWORD pcbOutput)
|
|
{
|
|
BOOL status = FALSE;
|
|
HMODULE hModule;
|
|
PNGCSIGNWITHSYMMETRICPOPKEY NgcSignWithSymmetricPopKey;
|
|
NTSTATUS ntStatus;
|
|
|
|
*ppbOutput = NULL;
|
|
*pcbOutput = 0;
|
|
|
|
hModule = LoadLibrary(L"cryptngc.dll");
|
|
if(hModule)
|
|
{
|
|
NgcSignWithSymmetricPopKey = (PNGCSIGNWITHSYMMETRICPOPKEY) GetProcAddress(hModule, "NgcSignWithSymmetricPopKey");
|
|
if(NgcSignWithSymmetricPopKey)
|
|
{
|
|
ntStatus = NgcSignWithSymmetricPopKey(pbKey, cbKey, pbLabel, cbLabel, pbContext, cbContext, pbData, cbData, ppbOutput, pcbOutput);
|
|
status = ntStatus == STATUS_SUCCESS;
|
|
if(!status)
|
|
PRINT_ERROR(L"NgcSignWithSymmetricPopKey: 0x%08x\n", ntStatus);
|
|
}
|
|
else PRINT_ERROR(L"No NgcSignWithSymmetricPopKey?\n");
|
|
FreeLibrary(hModule);
|
|
}
|
|
else PRINT_ERROR_AUTO(L"LoadLibrary");
|
|
return status;
|
|
}
|
|
|
|
PBYTE kull_m_crypto_ngc_pin_BinaryPinToPinProperty(LPCBYTE pbBinary, DWORD cbBinary, DWORD *pcbResult)
|
|
{
|
|
PWSTR data = NULL;
|
|
DWORD i, cbBuffer = cbBinary * 2 + 1;
|
|
|
|
if(data = (PWSTR) LocalAlloc(LPTR, cbBuffer * sizeof(wchar_t)))
|
|
{
|
|
for(i = 0; i < cbBinary; i++)
|
|
swprintf_s(data + i * 2, cbBuffer - i * 2, L"%02.2X", pbBinary[i]);
|
|
if(pcbResult)
|
|
*pcbResult = cbBuffer * sizeof(wchar_t);
|
|
}
|
|
return (PBYTE) data;
|
|
}
|
|
|
|
SECURITY_STATUS kull_m_crypto_ngc_hardware_unseal(NCRYPT_PROV_HANDLE hProv, LPCBYTE pbPin, DWORD cbPin, LPCBYTE pbInput, DWORD cbInput, PBYTE *ppOutput, DWORD *pcbOutput)
|
|
{
|
|
SECURITY_STATUS status;
|
|
NCRYPT_KEY_HANDLE hSealKey;
|
|
UNK_PIN uPin = {cbPin, 0x46, (PWSTR) pbPin};
|
|
UNK_PADDING uPadding = {0, 1, &uPin};
|
|
DWORD cbResult;
|
|
|
|
status = NCryptOpenKey(hProv, &hSealKey, TPM_RSA_SRK_SEAL_KEY, 0, NCRYPT_SILENT_FLAG);
|
|
if(status == ERROR_SUCCESS)
|
|
{
|
|
status = NCryptDecrypt(hSealKey, (PBYTE) pbInput, cbInput, &uPadding, NULL, 0, &cbResult, NCRYPT_SEALING_FLAG);
|
|
if(status == ERROR_SUCCESS)
|
|
{
|
|
if(*ppOutput = (PBYTE) LocalAlloc(LPTR, cbResult))
|
|
{
|
|
status = NCryptDecrypt(hSealKey, (PBYTE) pbInput, cbInput, &uPadding, *ppOutput, cbResult, pcbOutput, NCRYPT_SEALING_FLAG);
|
|
if(status != ERROR_SUCCESS)
|
|
{
|
|
PRINT_ERROR(L"NCryptDecrypt(data): 0x%08x\n", status);
|
|
*ppOutput = (PBYTE) LocalFree(*ppOutput);
|
|
*pcbOutput = 0;
|
|
}
|
|
}
|
|
else status = NTE_NO_MEMORY;
|
|
}
|
|
else PRINT_ERROR(L"NCryptDecrypt(init): 0x%08x\n", status);
|
|
NCryptFreeObject(hSealKey);
|
|
}
|
|
else PRINT_ERROR(L"NCryptOpenKey(seal): 0x%08x\n", status);
|
|
return status;
|
|
}
|
|
|
|
SECURITY_STATUS kull_m_crypto_ngc_software_decrypt(NCRYPT_PROV_HANDLE hProv, LPCWSTR szKeyName, LPCBYTE pbPin, DWORD cbPin, LPCBYTE pbInput, DWORD cbInput, PBYTE *ppOutput, DWORD *pcbOutput)
|
|
{
|
|
SECURITY_STATUS status;
|
|
NCRYPT_KEY_HANDLE hKey;
|
|
DWORD cbResult, dwSalt, dwIterations, dwSmartCardPin;
|
|
BYTE DerivedKey[32] = {0}, *SmartCardPin;
|
|
|
|
status = NCryptOpenKey(hProv, &hKey, szKeyName, 0, 0x4000); // ?
|
|
if(status == ERROR_SUCCESS)
|
|
{
|
|
status = NCryptGetProperty(hKey, L"NgcSoftwareKeyPbkdf2Salt", (PBYTE) &dwSalt, sizeof(dwSalt), &cbResult, 0x40000000 | NCRYPT_SILENT_FLAG); // ?
|
|
if(status == ERROR_SUCCESS)
|
|
{
|
|
status = NCryptGetProperty(hKey, L"NgcSoftwareKeyPbkdf2Round", (PBYTE) &dwIterations, sizeof(dwIterations), &cbResult, 0x40000000 | NCRYPT_SILENT_FLAG); // ?
|
|
if(status == ERROR_SUCCESS)
|
|
{
|
|
status = BCryptDeriveKeyPBKDF2(BCRYPT_HMAC_SHA256_ALG_HANDLE, (PUCHAR) pbPin, cbPin - sizeof(wchar_t), (PUCHAR) &dwSalt, sizeof(dwSalt), dwIterations, DerivedKey, sizeof(DerivedKey), 0);
|
|
if(status == ERROR_SUCCESS)
|
|
{
|
|
if(SmartCardPin = kull_m_crypto_ngc_pin_BinaryPinToPinProperty(DerivedKey, sizeof(DerivedKey), &dwSmartCardPin))
|
|
{
|
|
status = NCryptSetProperty(hKey, NCRYPT_PIN_PROPERTY, SmartCardPin, dwSmartCardPin - sizeof(wchar_t), NCRYPT_SILENT_FLAG);
|
|
if(status == ERROR_SUCCESS)
|
|
{
|
|
status = NCryptDecrypt(hKey, (PBYTE) pbInput, cbInput, NULL, NULL, 0, &cbResult, NCRYPT_PAD_PKCS1_FLAG | NCRYPT_SILENT_FLAG);
|
|
if(status == ERROR_SUCCESS)
|
|
{
|
|
if(*ppOutput = (PBYTE) LocalAlloc(LPTR, cbResult))
|
|
{
|
|
status = NCryptDecrypt(hKey, (PBYTE) pbInput, cbInput, NULL, *ppOutput, cbResult, pcbOutput, NCRYPT_PAD_PKCS1_FLAG | NCRYPT_SILENT_FLAG);
|
|
if(status != ERROR_SUCCESS)
|
|
{
|
|
PRINT_ERROR(L"NCryptDecrypt(data): 0x%08x\n", status);
|
|
*ppOutput = (PBYTE) LocalFree(*ppOutput);
|
|
*pcbOutput = 0;
|
|
}
|
|
}
|
|
else status = NTE_NO_MEMORY;
|
|
}
|
|
else PRINT_ERROR(L"NCryptDecrypt(init): 0x%08x\n", status);
|
|
}
|
|
else PRINT_ERROR(L"NCryptSetProperty(NCRYPT_PIN_PROPERTY): 0x%08x\n", status);
|
|
LocalFree(SmartCardPin);
|
|
}
|
|
else status = NTE_NO_MEMORY;
|
|
}
|
|
else PRINT_ERROR(L"BCryptDeriveKeyPBKDF2: 0x%08x\n", status);
|
|
}
|
|
else PRINT_ERROR(L"NCryptGetProperty(NgcSoftwareKeyPbkdf2Round): 0x%08x\n", status);
|
|
}
|
|
else PRINT_ERROR(L"NCryptGetProperty(NgcSoftwareKeyPbkdf2Salt): 0x%08x\n", status);
|
|
NCryptFreeObject(hKey);
|
|
}
|
|
else PRINT_ERROR(L"NCryptOpenKey(0x4000): 0x%08x\n", status);
|
|
|
|
return status;
|
|
} |