I am new to CNG. I am playing with the basic program from msdn site.
I have modified the input plain string and testing the output using other websites that provides the aes cbc encrypted output.
Unfortunately only first half matches and the next half is not matching.
It would be great if someone can point me where the mistake lies,
original code from msdn is here.
Here is the output generated from my code (below). Please note that there is no difference in my code apart from modifying the input plain string.
Here is the output from the online website (http://aes.online-domain-tools.com/ and anothersite)
The first half ends at "B0 C4 29 18".. after that the 2nd half doesn't match.
Here is the code snippet
#include <windows.h>
#include <stdio.h>
#include <bcrypt.h>
#pragma comment(lib, "bcrypt.lib")
#ifndef STATUS_UNSUCCESSFUL
#define STATUS_UNSUCCESSFUL ((NTSTATUS)0xC0000001L)
#endif // !STATUS_UNSUCCESSFUL
#ifndef NT_SUCCESS
#define NT_SUCCESS(Status) ((NTSTATUS)(Status) >= 0)
#endif
void
print_inhex(char *buf, int len) {
for (int i = 0; i < len; i++)
printf(" %02x", buf[i]);
printf("\n");
}
const BYTE rgbPlaintext[] =
{
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
};
static const BYTE rgbIV[] =
{
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
};
static const BYTE rgbAES128Key[] =
{
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
};
void
CNG_aes_cbc()
{
BCRYPT_ALG_HANDLE hAesAlg = NULL;
BCRYPT_KEY_HANDLE hKey = NULL;
NTSTATUS status = STATUS_UNSUCCESSFUL;
DWORD cbCipherText = 0,
cbPlainText = 0,
cbData = 0,
cbKeyObject = 0,
cbBlockLen = 0,
cbBlob = 0;
PBYTE pbCipherText = NULL,
pbPlainText = NULL,
pbKeyObject = NULL,
pbIV = NULL,
pbBlob = NULL;
// Open an algorithm handle.
if (!NT_SUCCESS(status = BCryptOpenAlgorithmProvider(&hAesAlg, BCRYPT_AES_ALGORITHM, NULL, 0))) {
wprintf(L"**** Error 0x%x returned by BCryptOpenAlgorithmProvider\n", status);
goto Cleanup;
}
// Calculate the size of the buffer to hold the KeyObject.
if (!NT_SUCCESS(status = BCryptGetProperty(hAesAlg, BCRYPT_OBJECT_LENGTH, (PBYTE)&cbKeyObject, sizeof(DWORD), &cbData, 0))) {
wprintf(L"**** Error 0x%x returned by BCryptGetProperty\n", status);
goto Cleanup;
}
// Allocate the key object on the heap.
pbKeyObject = (PBYTE)HeapAlloc(GetProcessHeap(), 0, cbKeyObject);
if (NULL == pbKeyObject) {
wprintf(L"**** memory allocation failed\n");
goto Cleanup;
}
// Calculate the block length for the IV.
if (!NT_SUCCESS(status = BCryptGetProperty(hAesAlg, BCRYPT_BLOCK_LENGTH, (PBYTE)&cbBlockLen, sizeof(DWORD), &cbData, 0))) {
wprintf(L"**** Error 0x%x returned by BCryptGetProperty\n", status);
goto Cleanup;
}
// Determine whether the cbBlockLen is not longer than the IV length.
if (cbBlockLen > sizeof(rgbIV)) {
wprintf(L"**** block length is longer than the provided IV length\n");
goto Cleanup;
}
// Allocate a buffer for the IV. The buffer is consumed during the
// encrypt/decrypt process.
pbIV = (PBYTE)HeapAlloc(GetProcessHeap(), 0, cbBlockLen);
if (NULL == pbIV) {
wprintf(L"**** memory allocation failed\n");
goto Cleanup;
}
memcpy(pbIV, rgbIV, cbBlockLen);
if (!NT_SUCCESS(status = BCryptSetProperty(hAesAlg, BCRYPT_CHAINING_MODE, (PBYTE)BCRYPT_CHAIN_MODE_CBC, sizeof(BCRYPT_CHAIN_MODE_CBC), 0))) {
wprintf(L"**** Error 0x%x returned by BCryptSetProperty\n", status);
goto Cleanup;
}
// Generate the key from supplied input key bytes.
if (!NT_SUCCESS(status = BCryptGenerateSymmetricKey(hAesAlg, &hKey, pbKeyObject, cbKeyObject, (PBYTE)rgbAES128Key, sizeof(rgbAES128Key), 0))) {
wprintf(L"**** Error 0x%x returned by BCryptGenerateSymmetricKey\n", status);
goto Cleanup;
}
// Save another copy of the key for later.
if (!NT_SUCCESS(status = BCryptExportKey(hKey, NULL, BCRYPT_KEY_DATA_BLOB, NULL, 0, &cbBlob, 0))) {
wprintf(L"**** Error 0x%x returned by BCryptExportKey\n", status);
goto Cleanup;
}
// Allocate the buffer to hold the BLOB.
PUCHAR pbBlob_1 = (PUCHAR)malloc(sizeof(PUCHAR) * cbBlob);
//pbBlob = (PBYTE)HeapAlloc(GetProcessHeap(), 0, cbBlob);
if (NULL == pbBlob_1) {
wprintf(L"**** memory allocation failed\n");
goto Cleanup;
}
if (!NT_SUCCESS(status = BCryptExportKey(hKey, NULL, BCRYPT_KEY_DATA_BLOB, pbBlob_1, cbBlob, &cbBlob, 0))) {
wprintf(L"**** Error 0x%x returned by BCryptExportKey\n", status);
goto Cleanup;
}
PUCHAR blob = pbBlob_1 + sizeof(BCRYPT_KEY_DATA_BLOB_HEADER);
int len = cbBlob - sizeof(BCRYPT_KEY_DATA_BLOB_HEADER);
printf("key:");
print_inhex(blob, len);
cbPlainText = sizeof(rgbPlaintext);
pbPlainText = (PBYTE)HeapAlloc(GetProcessHeap(), 0, cbPlainText);
if (NULL == pbPlainText) {
wprintf(L"**** memory allocation failed\n");
goto Cleanup;
}
/*memcpy(pbPlainText, rgbPlaintext, sizeof(rgbPlaintext));*/
char *test_msg = "This is my test msg";
cbPlainText = strlen(test_msg) + 1;
memcpy(pbPlainText, test_msg, cbPlainText);
printf("plain text:");
print_inhex(test_msg, strlen(test_msg));
// Get the output buffer size.
if (!NT_SUCCESS(status = BCryptEncrypt(hKey, pbPlainText, cbPlainText, NULL, pbIV, cbBlockLen, NULL, 0, &cbCipherText, BCRYPT_BLOCK_PADDING))) {
wprintf(L"**** Error 0x%x returned by BCryptEncrypt\n", status);
goto Cleanup;
}
pbCipherText = (PBYTE)HeapAlloc(GetProcessHeap(), 0, cbCipherText);
if (NULL == pbCipherText) {
wprintf(L"**** memory allocation failed\n");
goto Cleanup;
}
// Use the key to encrypt the plaintext buffer.
// For block sized messages, block padding will add an extra block.
if (!NT_SUCCESS(status = BCryptEncrypt(hKey, pbPlainText, cbPlainText, NULL, pbIV,
cbBlockLen, pbCipherText, cbCipherText, &cbData, BCRYPT_BLOCK_PADDING))){
wprintf(L"**** Error 0x%x returned by BCryptEncrypt\n", status);
goto Cleanup;
}
printf("cipher text:");
for (int i = 0; i < cbCipherText; i++)
printf(" %02x", pbCipherText[i]);
wprintf(L"\nSuccess!\n");
Cleanup:
if (hAesAlg)
BCryptCloseAlgorithmProvider(hAesAlg, 0);
if (hKey)
BCryptDestroyKey(hKey);
if (pbCipherText)
HeapFree(GetProcessHeap(), 0, pbCipherText);
if (pbKeyObject)
HeapFree(GetProcessHeap(), 0, pbKeyObject);
if (pbIV)
HeapFree(GetProcessHeap(), 0, pbIV);
}
You aren't consistent with your value for cbPlainText.
Asides:
You also have some very scary copy/realloc code where you write a string over a buffer not guaranteed as big as the string).
You also defined NT_SUCCESS in such a way that it returns whether or not something failed. 0 is success, !0 is failure.
You hex-printed up to strlen of tst_msg. But you set cbPlainText = strlen(tst_msg) + 1. If you set it to strlen(tst_msg) then you get #zaph's answer (46CC2228E81B2A05E8E8EBF2B0C42918EC496128D7C45BD0B19BB2D6452A3936).
You don't match the website because you used CNG with PKCS#7 padding, and the website uses zero-padding. You could identify the padding used in the website by taking your output ciphertext and putting it as the plaintext, then hitting decrypt. It then says your input was 54686973206973206d792074657374206d736700000000000000000000000000. Or, if you add 00 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C on your input to the website you'll get your original answer. Or add 0D 0D 0D 0D 0D 0D 0D 0D 0D 0D 0D 0D 0D and you'll get #zaph's answer.
So, things to do:
Don't re-evaluate the length of things to print, make one variable (cbPlainText) and stick with it.
AES is a block cipher algorithm. All block ciphers require complete blocks, a deficient last block must be padded (and under removable padding schemes a complete final block requires yet another block). Learn what this means before continuing. https://en.wikipedia.org/wiki/Padding_(cryptography)#Symmetric_cryptography
When something seems wrong with encryption, look at the decrypted output.
Very often the decrypted output with "no padding" is revealing.
Learn C, and how memory works. Or switch to C# and have a less steep learning curve.
The length of the data is not an exact multiple of the block size (16-bytes for AES) so padding is added but. That is where the implementation either rejects the data, pads with a default method such as 0x00 (cryptomathic), PKCS#7 (the generally used padding) or whatever junk follews the provided data in memory.
Don't use BCryptEncrypt, use AES Class
SymmetricAlgorithm.Padding Property Note: The default is PaddingMode.PKCS7.
It is best to specify the padding on instantiation of AES.
See PaddingMode Enumeration: PKCS7
The PKCS #7 padding string consists of a sequence of bytes, each of which is equal to the total number of padding bytes added.
Manually adding PKCS#7 padding to:
cryptommathic AES:
produces: 46CC2228E81B2A05E8E8EBF2B0C42918EC496128D7C45BD0B19BB2D6452A3936
Related
Hi i want execute binary code of a exe / dll file from memory and i found this code:
#include <iostream> // Standard C++ library for console I/O
#include <string> // Standard C++ Library for string manip
#include <Windows.h> // WinAPI Header
#include <TlHelp32.h> //WinAPI Process API
int RunPortableExecutable(void* Image)
{
IMAGE_DOS_HEADER* DOSHeader; // For Nt DOS Header symbols
IMAGE_NT_HEADERS* NtHeader; // For Nt PE Header objects & symbols
IMAGE_SECTION_HEADER* SectionHeader;
PROCESS_INFORMATION PI;
STARTUPINFOA SI;
CONTEXT* CTX;
DWORD* ImageBase; //Base address of the image
void* pImageBase; // Pointer to the image base
int count;
char CurrentFilePath[1024];
DOSHeader = PIMAGE_DOS_HEADER(Image); // Initialize Variable
NtHeader = PIMAGE_NT_HEADERS(DWORD(Image) + DOSHeader->e_lfanew); // Initialize
GetModuleFileNameA(0, CurrentFilePath, 1024); // path to current executable
if (NtHeader->Signature == IMAGE_NT_SIGNATURE) // Check if image is a PE File.
{
ZeroMemory(&PI, sizeof(PI)); // Null the memory
ZeroMemory(&SI, sizeof(SI)); // Null the memory
if (CreateProcessA(CurrentFilePath, NULL, NULL, NULL, FALSE,
CREATE_SUSPENDED, NULL, NULL, &SI, &PI)) // Create a new instance of current
//process in suspended state, for the new image.
{
// Allocate memory for the context.
CTX = LPCONTEXT(VirtualAlloc(NULL, sizeof(CTX), MEM_COMMIT, PAGE_READWRITE));
CTX->ContextFlags = CONTEXT_FULL; // Context is allocated
if (GetThreadContext(PI.hThread, LPCONTEXT(CTX))) //if context is in thread
{
// Read instructions
ReadProcessMemory(PI.hProcess, LPCVOID(CTX->Ebx + 8), LPVOID(&ImageBase), 4, 0);
pImageBase = VirtualAllocEx(PI.hProcess, LPVOID(NtHeader->OptionalHeader.ImageBase),
NtHeader->OptionalHeader.SizeOfImage, 0x3000, PAGE_EXECUTE_READWRITE);
// Write the image to the process
WriteProcessMemory(PI.hProcess, pImageBase, Image, NtHeader->OptionalHeader.SizeOfHeaders, NULL);
for (count = 0; count < NtHeader->FileHeader.NumberOfSections; count++)
{
SectionHeader = PIMAGE_SECTION_HEADER(DWORD(Image) + DOSHeader->e_lfanew + 248 + (count * 40));
WriteProcessMemory(PI.hProcess, LPVOID(DWORD(pImageBase) + SectionHeader->VirtualAddress),
LPVOID(DWORD(Image) + SectionHeader->PointerToRawData), SectionHeader->SizeOfRawData, 0);
}
WriteProcessMemory(PI.hProcess, LPVOID(CTX->Ebx + 8),
LPVOID(&NtHeader->OptionalHeader.ImageBase), 4, 0);
// Move address of entry point to the eax register
CTX->Eax = DWORD(pImageBase) + NtHeader->OptionalHeader.AddressOfEntryPoint;
SetThreadContext(PI.hThread, LPCONTEXT(CTX)); // Set the context
ResumeThread(PI.hThread); //´Start the process/call main()
return 0; // Operation was successful.
}
}
}
}
// enter valid bytes of a program here.
unsigned char rawData[37376] = {
0x4D, 0x5A, 0x90, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0x00, 0x00, 0xB8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
int main()
{
RunPortableExecutable(rawData); // run executable from the array
getchar();
}
This code i found on github when i start it it just waits does nothing:
Than i replaced my own binary codes to project like this:
Its too long so im sharing a picture.
When i debug it i see this error:
But also sometimes works?!
What is problem? and how to solve? thats really weird :/
this is what i use on visual studio (sorry im new and extremelly noob :D)
Remember that you're forking the same process and rewriting the process memory with your custom PE file, so when the Process starts it will start as a child of the stub executable, and seems that you're not waiting for the object to return
WaitForSingleObject(
PI.hProcess,
INFINITE
);
GetExitCodeProcess(
PI.hProcess,
&dwRet
);
CloseHandle(PI.hThread);
CloseHandle(PI.hProcess);
Also you might be interested in attaching the child process to some debugger (i.e x64dbg) and check if it's raising any exception itself.
The target program is an x86 program, I tried to use the following code to call MessageBoxA, the program did not report an error, but MessageBoxA did not execute either
const char* title = "hello";
const char* content = "world";
size_t titleLen = strlen(title) + 1;
size_t contentLen = strlen(content) + 1;
size_t size = titleLen + contentLen + sizeof(DWORD) * 4;
BYTE* newmem = (BYTE*)VirtualAllocEx(gc.hProcess, 0, size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
printf("newmem: %x\n", newmem);
DWORD titleAddr = (DWORD)newmem;
DWORD contentAddr = titleAddr + titleLen;
DWORD paramsAddr = contentAddr + contentLen;
WriteProcessMemory(gc.hProcess, (LPVOID)titleAddr, (LPCVOID)title, titleLen, 0);
WriteProcessMemory(gc.hProcess, (LPVOID)contentAddr, (LPCVOID)content, contentLen, 0);
DWORD p1 = 0;
DWORD p4 = 0;
printf("paramsAddr %x\n", paramsAddr);
WriteProcessMemory(gc.hProcess, (LPVOID)paramsAddr, (LPCVOID)&p1, sizeof(DWORD), 0);
WriteProcessMemory(gc.hProcess, (LPVOID)(paramsAddr + 4), (LPCVOID)&titleAddr, sizeof(DWORD), 0);
WriteProcessMemory(gc.hProcess, (LPVOID)(paramsAddr + 8), (LPCVOID)&contentAddr, sizeof(DWORD), 0);
WriteProcessMemory(gc.hProcess, (LPVOID)(paramsAddr + 12), (LPCVOID)&p4, sizeof(DWORD), 0);
HANDLE hThread = CreateRemoteThread(gc.hProcess, 0, 0,
(LPTHREAD_START_ROUTINE)MessageBoxA, (LPVOID)paramsAddr,
0, 0);
printf("hThread %d\n", hThread);
WaitForSingleObject(hThread, INFINITE);
VirtualFreeEx(gc.hProcess, newmem, 0, MEM_RELEASE);
CloseHandle(hThread);
This is some information at runtime:
newmem: 5f0000
paramsAddr 5f000c
5f0000: 68 65 6C 6C 6F 00 77 6F 72 6C 64 00
00 00 00 00
00 00 5F 00
06 00 5F 00
00 00 00 00
I try to call ExitProcess function can be executed normally
HANDLE hThread = CreateRemoteThread(gc.hProcess, 0, 0,
(LPTHREAD_START_ROUTINE)ExitProcess, 0,
0, 0);
Is the call to MessageBoxA failing because of passing wrong parameters? I need some help, thanks
This is a hard-coded version that can execute MessageBoxA
const char* title = "hello";
const char* content = "world";
size_t titleLen = strlen(title) + 1;
size_t contentLen = strlen(content) + 1;
BYTE* newmem = (BYTE*)VirtualAllocEx(gc.hProcess, 0, 1024, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
printf("newmem: %x\n", newmem);
DWORD titleAddr = (DWORD)newmem;
DWORD contentAddr = titleAddr + titleLen;
DWORD funAddr = contentAddr + contentLen;
WriteProcessMemory(gc.hProcess, (LPVOID)titleAddr, (LPCVOID)title, titleLen, 0);
WriteProcessMemory(gc.hProcess, (LPVOID)contentAddr, (LPCVOID)content, contentLen, 0);
/*
3 00000000 6A00 push 0
4 00000002 6878563412 push 0x12345678
5 00000007 6878563412 push 0x12345678
6 0000000C 6A00 push 0
7 0000000E E800000000 call MessageBoxA
8 00000013 C3 ret
*/
BYTE funcode[] = {
0x6A, 0x00,
0x68, 0x00,0x00,0x00,0x00,
0x68, 0x00,0x00,0x00,0x00,
0x6A, 0x00,
0xE8, 0x00,0x00,0x00,0x00,
0xC3
};
DWORD pMessageBoxA = 0x76E013D0;
DWORD MessageBoxA = pMessageBoxA - (funAddr + 0xE) - 5;
memcpy_s(funcode + 0x3, 4, &titleAddr, 4);
memcpy_s(funcode + 0x8, 4, &contentAddr, 4);
memcpy_s(funcode + 0xF, 4, &MessageBoxA, 4);
WriteProcessMemory(gc.hProcess, (LPVOID)funAddr, funcode, sizeof(funcode), 0);
HANDLE hThread = CreateRemoteThread(gc.hProcess, 0, 0,
(LPTHREAD_START_ROUTINE)funAddr, 0, 0, 0);
WaitForSingleObject(hThread, INFINITE);
VirtualFreeEx(gc.hProcess, newmem, 0, MEM_RELEASE);
CloseHandle(hThread);
This is a common code on x86 and x64. If your target program is x86/x64, then your program also needs to be compiled to x86/x64. I tested several programs to work normally.
uintptr_t pMessageBoxA = GetProcAddressEx(gc.hProcess, "user32.dll", "MessageBoxA");
if (!pMessageBoxA)
{
printf("target not find MessageBoxA\n");
return 0;
}
printf("pMessageBoxA: %lp\n", pMessageBoxA);
const char* title = "hello";
const char* content = "world";
size_t titleLen = strlen(title) + 1;
size_t contentLen = strlen(content) + 1;
BYTE* newmem = (BYTE*)VirtualAllocEx(gc.hProcess, 0, 1024, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
printf("newmem: %x\n", newmem);
uintptr_t titleAddr = (uintptr_t)newmem;
uintptr_t contentAddr = titleAddr + titleLen;
uintptr_t funAddr = contentAddr + contentLen + 8;
printf("funAddr: %x\n", funAddr);
WriteProcessMemory(gc.hProcess, (LPVOID)titleAddr, (LPCVOID)title, titleLen, 0);
WriteProcessMemory(gc.hProcess, (LPVOID)contentAddr, (LPCVOID)content, contentLen, 0);
#ifdef _WIN64
/*
0000- 55 - push rbp
0001- 48 8B EC - mov rbp,rsp
0004- 48 83 EC 20 - sub rsp,20
0008- 48 B9 0000000000000000 - mov rcx,0000000000000000
0012- 48 BA 0000000000000000 - mov rdx,0000000000000000
001C- 49 B8 0000000000000000 - mov r8,0000000000000000
0026- 49 B9 0000000000000000 - mov r9,0000000000000000
0030- 48 B8 E02C643FFD7F0000 - mov rax,user32.MessageBoxA
003A- FF D0 - call rax
003C- 48 83 C4 20 - add rsp,20
0040- 48 8B E5 - mov rsp,rbp
0043- 5D - pop rbp
0044- C3 - ret
*/
BYTE funcode[] = {
0x55,
0x48, 0x8B, 0xEC,
0x48, 0x83, 0xEC, 0x20,
0x48, 0xB9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x48, 0xBA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x49, 0xB8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x49, 0xB9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x48, 0xB8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xD0,
0x48, 0x83, 0xC4, 0x20,
0x48, 0x8B, 0xE5,
0x5D,
0xC3,
};
memcpy_s(funcode + 0x14, sizeof(uintptr_t), &contentAddr, sizeof(uintptr_t)); // rdx
memcpy_s(funcode + 0x1E, sizeof(uintptr_t), &titleAddr, sizeof(uintptr_t)); // r8
memcpy_s(funcode + 0x32, sizeof(uintptr_t), &pMessageBoxA, sizeof(uintptr_t)); // rax
WriteProcessMemory(gc.hProcess, (LPVOID)funAddr, funcode, sizeof(funcode), 0);
#else
/*
3 00000000 6A00 push 0
4 00000002 6878563412 push 0x12345678
5 00000007 6878563412 push 0x12345678
6 0000000C 6A00 push 0
7 0000000E E800000000 call MessageBoxA
8 00000013 C3 ret
*/
BYTE funcode[] = {
0x6A, 0x00,
0x68, 0x00,0x00,0x00,0x00,
0x68, 0x00,0x00,0x00,0x00,
0x6A, 0x00,
0xE8, 0x00,0x00,0x00,0x00,
0xC3
};
DWORD MessageBoxA = pMessageBoxA - (funAddr + 0xE) - 5;
memcpy_s(funcode + 0x3, sizeof(DWORD), &titleAddr, sizeof(DWORD));
memcpy_s(funcode + 0x8, sizeof(DWORD), &contentAddr, sizeof(DWORD));
memcpy_s(funcode + 0xF, sizeof(DWORD), &MessageBoxA, sizeof(DWORD));
WriteProcessMemory(gc.hProcess, (LPVOID)funAddr, funcode, sizeof(funcode), 0);
#endif // _WIN64
HANDLE hThread = CreateRemoteThread(gc.hProcess, 0, 0, (LPTHREAD_START_ROUTINE)funAddr, 0, 0, 0);
WaitForSingleObject(hThread, INFINITE);
VirtualFreeEx(gc.hProcess, newmem, 0, MEM_RELEASE);
CloseHandle(hThread);
GetProcAddressEx:
uintptr_t GetProcAddressEx(HANDLE hProcess, string modName, string exportFunName)
{
MODULEINFO mi = GetModuleBase(modName, GetProcessId(hProcess));
uintptr_t moduleBaseAddr = (uintptr_t)mi.lpBaseOfDll;
// is PE FILE ?
WORD e_magic = 0;
ReadProcessMemory(hProcess, (LPCVOID)moduleBaseAddr, &e_magic, sizeof(WORD), 0);
if (e_magic != 0x5A4D)
{
printf("not PE file.\n");
return 0;
}
// get ntHeader offset
DWORD e_lfanew = 0;
ReadProcessMemory(hProcess, (LPCVOID)(moduleBaseAddr + 0x3C), &e_lfanew, sizeof(DWORD), 0);
uintptr_t ntHeaderAddr = moduleBaseAddr + e_lfanew;
uintptr_t fileHeaderAddr = ntHeaderAddr + sizeof(DWORD);
// x86 is 0xE0, x64 is 0xF0
WORD optHeaderSize = 0;
ReadProcessMemory(hProcess, (LPCVOID)(fileHeaderAddr + 0x10), &optHeaderSize, sizeof(WORD), 0);
// tables
uintptr_t DataDirectoryAddr = fileHeaderAddr + sizeof(IMAGE_FILE_HEADER) + optHeaderSize - sizeof(IMAGE_DATA_DIRECTORY) * 16;
// tables[0] is export table
IMAGE_DATA_DIRECTORY exportEntry;
ReadProcessMemory(hProcess, (LPCVOID)DataDirectoryAddr, &exportEntry, sizeof(IMAGE_DATA_DIRECTORY), 0);
if (!exportEntry.Size)
{
printf("not export table. \n");
return 0;
}
auto RVA2VA = [&](uintptr_t rva) -> uintptr_t
{
return moduleBaseAddr + rva;
};
uintptr_t exportDirDataAddr = RVA2VA(exportEntry.VirtualAddress);
// the number of use name export function
DWORD NumberOfNames = 0;
ReadProcessMemory(hProcess, (LPCVOID)(exportDirDataAddr + 0x18), &NumberOfNames, sizeof(DWORD), 0);
DWORD AddressOfFunctions = 0;
ReadProcessMemory(hProcess, (LPCVOID)(exportDirDataAddr + 0x1C), &AddressOfFunctions, sizeof(DWORD), 0);
DWORD* AddressOfFunctionsVA = (DWORD*)RVA2VA(AddressOfFunctions);
// function name table
DWORD AddressOfNames = 0;
ReadProcessMemory(hProcess, (LPCVOID)(exportDirDataAddr + 0x20), &AddressOfNames, sizeof(DWORD), 0);
DWORD* AddressOfNamesVA = (DWORD*)RVA2VA(AddressOfNames);
DWORD AddressOfNameOrdinals = 0;
ReadProcessMemory(hProcess, (LPCVOID)(exportDirDataAddr + 0x24), &AddressOfNameOrdinals, sizeof(DWORD), 0);
WORD* AddressOfNameOrdinalsVA = (WORD*)RVA2VA(AddressOfNameOrdinals);
auto readASCII = [&](uintptr_t addr, char* name) -> void
{
size_t i = 0;
char c;
while (true)
{
ReadProcessMemory(hProcess, (LPCVOID)(addr + i), &c, sizeof(BYTE), 0);
name[i] = c;
if (!c) break;
i++;
}
};
DWORD itRVA = 0;
char funName[1024];
size_t funNameIndex = 0;
for (; funNameIndex < NumberOfNames; funNameIndex++)
{
ReadProcessMemory(hProcess, AddressOfNamesVA + funNameIndex, &itRVA, sizeof(DWORD), 0);
readASCII(moduleBaseAddr + itRVA, funName);
if (!strcmp(funName, exportFunName.c_str()))
break;
}
if (strlen(funName) == 0)
{
return 0;
}
// get function address index
WORD AddressOfFunctionsIndex = 0;
ReadProcessMemory(hProcess, AddressOfNameOrdinalsVA + funNameIndex, &AddressOfFunctionsIndex, sizeof(WORD), 0);
// get function address
DWORD funAddrRVA = 0;
ReadProcessMemory(hProcess, AddressOfFunctionsVA + AddressOfFunctionsIndex, &funAddrRVA, sizeof(DWORD), 0);
return RVA2VA(funAddrRVA);
}
GetModuleBase:
MODULEINFO GetModuleBase(string moduleName, DWORD pid)
{
MODULEINFO mi{ 0 };
HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, pid);
if (hSnap != INVALID_HANDLE_VALUE)
{
MODULEENTRY32 me;
me.dwSize = sizeof(me);
if (Module32First(hSnap, &me))
{
do {
if (!_wcsicmp(me.szModule, toWstring(moduleName).c_str()))
{
mi.lpBaseOfDll = me.modBaseAddr;
mi.SizeOfImage = me.modBaseSize;
break;
}
} while (Module32Next(hSnap, &me));
}
}
CloseHandle(hSnap);
return mi;
}
Compared with hard-coded code, this is more complicated.
If you want to get the parameters passed by CreateRemoteThread
BYTE* lpParam = (BYTE*)VirtualAllocEx(gc.hProcess, 0, 8, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
DWORD p1 = 1;
DWORD p2 = 2;
WriteProcessMemory(gc.hProcess, lpParam, &p1, sizeof(DWORD), 0);
WriteProcessMemory(gc.hProcess, lpParam + 4, &p2, sizeof(DWORD), 0);
printf("lpParam: %lp\n", lpParam);
HANDLE hThread = CreateRemoteThread(gc.hProcess, 0, 0, (LPTHREAD_START_ROUTINE)funAddr, lpParam, 0, 0);
If the target program is x86 then you can get lpParam in [esp+4]
If the target program is x64 then you can get lpParam in rcx
So I am pondering which cryptographic C++ library to use (I already figured out how to do equivalent in C#) for the verification of a licence file signed hash.
Reading the Microsoft documentation for CNG it seems that it is not possible to generate an ECDSA key in code from a stream of bytes despite this being possible for a RSA key (I think, not 100% sure).
Because I wanted in code byte stream generation, I looked at crypto++ and I managed to get the test suite compiled but cryptolib.lib is an outsize 90 megabytes and I am facing a slew of link errors simply trying to do something basic. So I am less keen in crypto++ now.
So I want to turn back to using something shipped by Microsoft in its desktop Windows OS but I am back to my original problem of no in code bytestream generated keys.
Can an expert confirm that this really isn't possible? Also, can they suggest alternative, I am happy to fall back to RSA with a long (2048?) key.
The following code compiles and runs for me. It can be found at the MSDN article -
Signing Data with CNG. I was wondering if it could be adapted. Does this code (a) create an ECDSA key on the fly (b) sign a hash (c) save key to a certificate store (d) retrieve the key and verify signed hash. If so then I guess it's demo code. What I would need is an example of a hard coded ECDSA key not one created on the fly.
// CngECDSA.cpp : Defines the entry point for the console application.
// Based on https://msdn.microsoft.com/en-us/library/windows/desktop/aa376304(v=vs.85).aspx
#include "stdafx.h"
#include <Windows.h>
#include <stdint.h>
#include <Bcrypt.h>
#include <ncrypt.h>
#pragma comment(lib, "bcrypt")
#pragma comment(lib, "ncrypt")
#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)
#define STATUS_UNSUCCESSFUL ((NTSTATUS)0xC0000001L)
static const BYTE rgbMsg[] =
{
0x04, 0x87, 0xec, 0x66, 0xa8, 0xbf, 0x17, 0xa6,
0xe3, 0x62, 0x6f, 0x1a, 0x55, 0xe2, 0xaf, 0x5e,
0xbc, 0x54, 0xa4, 0xdc, 0x68, 0x19, 0x3e, 0x94,
};
BYTE value[] =
{ 0x02,0x00,0x00,0x00 };
void __cdecl wmain(
int argc,
__in_ecount(argc) LPWSTR *wargv)
{
NCRYPT_PROV_HANDLE hProv = NULL;
NCRYPT_KEY_HANDLE hKey = NULL;
BCRYPT_KEY_HANDLE hTmpKey = NULL;
SECURITY_STATUS secStatus = ERROR_SUCCESS;
BCRYPT_ALG_HANDLE hHashAlg = NULL,
hSignAlg = NULL;
BCRYPT_HASH_HANDLE hHash = NULL;
NTSTATUS status = STATUS_UNSUCCESSFUL;
DWORD cbData = 0,
cbHash = 0,
cbBlob = 0,
cbSignature = 0,
cbHashObject = 0;
PBYTE pbHashObject = NULL;
PBYTE pbHash = NULL,
pbBlob = NULL,
pbSignature = NULL;
UNREFERENCED_PARAMETER(argc);
UNREFERENCED_PARAMETER(wargv);
//open an algorithm handle
if (!NT_SUCCESS(status = BCryptOpenAlgorithmProvider(
&hHashAlg,
BCRYPT_SHA1_ALGORITHM,
NULL,
0)))
{
wprintf(L"**** Error 0x%x returned by BCryptOpenAlgorithmProvider\n", status);
goto Cleanup;
}
if (!NT_SUCCESS(status = BCryptOpenAlgorithmProvider(
&hSignAlg,
BCRYPT_ECDSA_P256_ALGORITHM,
NULL,
0)))
{
wprintf(L"**** Error 0x%x returned by BCryptOpenAlgorithmProvider\n", status);
goto Cleanup;
}
//calculate the size of the buffer to hold the hash object
if (!NT_SUCCESS(status = BCryptGetProperty(
hHashAlg,
BCRYPT_OBJECT_LENGTH,
(PBYTE)&cbHashObject,
sizeof(DWORD),
&cbData,
0)))
{
wprintf(L"**** Error 0x%x returned by BCryptGetProperty\n", status);
goto Cleanup;
}
//allocate the hash object on the heap
pbHashObject = (PBYTE)HeapAlloc(GetProcessHeap(), 0, cbHashObject);
if (NULL == pbHashObject)
{
wprintf(L"**** memory allocation failed\n");
goto Cleanup;
}
//calculate the length of the hash
if (!NT_SUCCESS(status = BCryptGetProperty(
hHashAlg,
BCRYPT_HASH_LENGTH,
(PBYTE)&cbHash,
sizeof(DWORD),
&cbData,
0)))
{
wprintf(L"**** Error 0x%x returned by BCryptGetProperty\n", status);
goto Cleanup;
}
//allocate the hash buffer on the heap
pbHash = (PBYTE)HeapAlloc(GetProcessHeap(), 0, cbHash);
if (NULL == pbHash)
{
wprintf(L"**** memory allocation failed\n");
goto Cleanup;
}
//create a hash
if (!NT_SUCCESS(status = BCryptCreateHash(
hHashAlg,
&hHash,
pbHashObject,
cbHashObject,
NULL,
0,
0)))
{
wprintf(L"**** Error 0x%x returned by BCryptCreateHash\n", status);
goto Cleanup;
}
//hash some data
if (!NT_SUCCESS(status = BCryptHashData(
hHash,
(PBYTE)rgbMsg,
sizeof(rgbMsg),
0)))
{
wprintf(L"**** Error 0x%x returned by BCryptHashData\n", status);
goto Cleanup;
}
//close the hash
if (!NT_SUCCESS(status = BCryptFinishHash(
hHash,
pbHash,
cbHash,
0)))
{
wprintf(L"**** Error 0x%x returned by BCryptFinishHash\n", status);
goto Cleanup;
}
//open handle to KSP
if (FAILED(secStatus = NCryptOpenStorageProvider(
&hProv,
MS_KEY_STORAGE_PROVIDER,
0)))
{
wprintf(L"**** Error 0x%x returned by NCryptOpenStorageProvider\n", secStatus);
goto Cleanup;
}
//create a persisted key
if (FAILED(secStatus = NCryptCreatePersistedKey(
hProv,
&hKey,
NCRYPT_ECDSA_P256_ALGORITHM,
L"my ecc key",
0,
0)))
{
wprintf(L"**** Error 0x%x returned by NCryptCreatePersistedKey\n", secStatus);
goto Cleanup;
}
//create key on disk
if (FAILED(secStatus = NCryptFinalizeKey(hKey, 0)))
{
wprintf(L"**** Error 0x%x returned by NCryptFinalizeKey\n", secStatus);
goto Cleanup;
}
//sign the hash
if (FAILED(secStatus = NCryptSignHash(
hKey,
NULL,
pbHash,
cbHash,
NULL,
0,
&cbSignature,
0)))
{
wprintf(L"**** Error 0x%x returned by NCryptSignHash\n", secStatus);
goto Cleanup;
}
//allocate the signature buffer
pbSignature = (PBYTE)HeapAlloc(GetProcessHeap(), 0, cbSignature);
if (NULL == pbSignature)
{
wprintf(L"**** memory allocation failed\n");
goto Cleanup;
}
if (FAILED(secStatus = NCryptSignHash(
hKey,
NULL,
pbHash,
cbHash,
pbSignature,
cbSignature,
&cbSignature,
0)))
{
wprintf(L"**** Error 0x%x returned by NCryptSignHash\n", secStatus);
goto Cleanup;
}
if (FAILED(secStatus = NCryptExportKey(
hKey,
NULL,
BCRYPT_ECCPUBLIC_BLOB,
NULL,
NULL,
0,
&cbBlob,
0)))
{
wprintf(L"**** Error 0x%x returned by NCryptExportKey\n", secStatus);
goto Cleanup;
}
pbBlob = (PBYTE)HeapAlloc(GetProcessHeap(), 0, cbBlob);
if (NULL == pbBlob)
{
wprintf(L"**** memory allocation failed\n");
goto Cleanup;
}
if (FAILED(secStatus = NCryptExportKey(
hKey,
NULL,
BCRYPT_ECCPUBLIC_BLOB,
NULL,
pbBlob,
cbBlob,
&cbBlob,
0)))
{
wprintf(L"**** Error 0x%x returned by NCryptExportKey\n", secStatus);
goto Cleanup;
}
if (!NT_SUCCESS(status = BCryptImportKeyPair(
hSignAlg,
NULL,
BCRYPT_ECCPUBLIC_BLOB,
&hTmpKey,
pbBlob,
cbBlob,
0)))
{
wprintf(L"**** Error 0x%x returned by BCryptImportKeyPair\n", status);
goto Cleanup;
}
if (!NT_SUCCESS(status = BCryptVerifySignature(
hTmpKey,
NULL,
pbHash,
cbHash,
pbSignature,
cbSignature,
0)))
{
wprintf(L"**** Error 0x%x returned by BCryptVerifySignature\n", status);
goto Cleanup;
}
wprintf(L"Success!\n");
Cleanup:
if (hHashAlg)
{
BCryptCloseAlgorithmProvider(hHashAlg, 0);
}
if (hSignAlg)
{
BCryptCloseAlgorithmProvider(hSignAlg, 0);
}
if (hHash)
{
BCryptDestroyHash(hHash);
}
if (pbHashObject)
{
HeapFree(GetProcessHeap(), 0, pbHashObject);
}
if (pbHash)
{
HeapFree(GetProcessHeap(), 0, pbHash);
}
if (pbSignature)
{
HeapFree(GetProcessHeap(), 0, pbSignature);
}
if (pbBlob)
{
HeapFree(GetProcessHeap(), 0, pbBlob);
}
if (hTmpKey)
{
BCryptDestroyKey(hTmpKey);
}
if (hKey)
{
NCryptDeleteKey(hKey, 0);
}
if (hProv)
{
NCryptFreeObject(hProv);
}
}
Just to be clear, I aiming at 384 bit and for compatibility with OpenSsl and C# curvename is NIST recommended curve secp384r1 – {1.3.132.0.34} And I will be using SHA256 hash twice (just like BitCoin).
Does this code (a) create an ECDSA key on the fly (b) sign a hash (c) save key to a certificate store (d) retrieve the key and verify signed hash. If so then I guess it's demo code.
A) Yes.
B) Yes.
C) Yes. It saves the key as a persisted object named "my ec key". But since it never asked for it by name again, nullptr/NULL could have been passed to make it be an ephemeral key. (And it saved it to the "key store", not a "certificate store".
D) Yes to verify, no to retrieve.
Getting your publicKey data (this is the output of openssl ec -in eckey.pem -pubout -outform der | xxd -g1 translated into the C array) and signature (in the IEEE P1363 format) is an exercise left to the reader.
static const BYTE data[] =
{
'1', '2', '3', '4',
};
static const BYTE publicKey[] =
{
0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86,
0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a,
0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03,
0x42, 0x00, 0x04, 0x23, 0x63, 0xdd, 0x13, 0x1d,
0xa6, 0x5e, 0x89, 0x9a, 0x2e, 0x63, 0xe9, 0xe0,
0x5e, 0x50, 0xc8, 0x30, 0xd4, 0x99, 0x46, 0x62,
0xff, 0xe8, 0x83, 0xdb, 0x2b, 0x9a, 0x76, 0x7d,
0xcc, 0xab, 0xa2, 0xf0, 0x70, 0x81, 0xb5, 0x71,
0x1b, 0xe1, 0xde, 0xe9, 0x0d, 0xfc, 0x8d, 0xe1,
0x79, 0x70, 0xc2, 0xd9, 0x37, 0xa1, 0x6c, 0xd3,
0x45, 0x81, 0xf5, 0x2b, 0x8d, 0x59, 0xc9, 0xe9,
0x53, 0x2d, 0x13,
};
static const BYTE signature[] =
{
// r
0xc6, 0x4c, 0x14, 0x55, 0xfe, 0xc0, 0x2f, 0xe7,
0x4a, 0x25, 0x87, 0xe7, 0x0c, 0x10, 0x4e, 0x73,
0xf0, 0x28, 0x86, 0x18, 0x28, 0xae, 0xef, 0x4f,
0xe5, 0xa0, 0xcc, 0x7a, 0xa8, 0xe4, 0x1f, 0xbf,
// s
0x35, 0x9f, 0x23, 0xfd, 0xc3, 0xd6, 0x33, 0xfb,
0x52, 0x47, 0x9b, 0xef, 0x2b, 0x2a, 0x48, 0xa8,
0x6f, 0x37, 0x04, 0xd0, 0x8c, 0xc3, 0x49, 0x04,
0x21, 0x53, 0xb8, 0x3c, 0x9d, 0x8c, 0x6c, 0xf5,
};
#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)
int main()
{
NTSTATUS status = NTE_BAD_DATA;
int exitCode = ERROR_INVALID_FUNCTION;
BCRYPT_KEY_HANDLE importedPublicKey = nullptr;
PCERT_PUBLIC_KEY_INFO subjectPublicKeyInfo = (PCERT_PUBLIC_KEY_INFO)LocalAlloc(0, 2048);
BCRYPT_ALG_HANDLE sha256 = nullptr;
BCRYPT_HASH_HANDLE hHash = nullptr;
BYTE dataHash[256 >> 3];
DWORD structSize = 2048;
if (!CryptDecodeObject(
X509_ASN_ENCODING,
X509_PUBLIC_KEY_INFO,
publicKey,
sizeof(publicKey),
0,
subjectPublicKeyInfo,
&structSize))
{
wprintf(L"**** Error 0x%x returned by CryptDecodeObject\n", GetLastError());
goto Cleanup;
}
if (!CryptImportPublicKeyInfoEx2(
X509_ASN_ENCODING,
subjectPublicKeyInfo,
0,
nullptr,
&importedPublicKey))
{
wprintf(L"**** Error 0x%x returned by CryptImportPublicKeyInfoEx2\n", GetLastError());
goto Cleanup;
}
if (!NT_SUCCESS(status = BCryptOpenAlgorithmProvider(&sha256, BCRYPT_SHA256_ALGORITHM, nullptr, 0)))
{
wprintf(L"**** Error 0x%x returned by BCryptOpenAlgorithmProvider\n", status);
goto Cleanup;
}
if (!NT_SUCCESS(status = BCryptCreateHash(sha256, &hHash, nullptr, 0, nullptr, 0, 0)))
{
wprintf(L"**** Error 0x%x returned by BCryptCreateHash\n", status);
goto Cleanup;
}
if (!NT_SUCCESS(status = BCryptHashData(hHash, (PUCHAR)data, sizeof(data), 0)))
{
wprintf(L"**** Error 0x%x returned by BCryptHashData\n", status);
goto Cleanup;
}
if (!NT_SUCCESS(status = BCryptFinishHash(hHash, (PUCHAR)dataHash, sizeof(dataHash), 0)))
{
wprintf(L"**** Error 0x%x returned by BCryptFinishHash\n", status);
goto Cleanup;
}
status = BCryptVerifySignature(
importedPublicKey,
nullptr,
(PUCHAR)dataHash,
sizeof(dataHash),
(PUCHAR)signature,
sizeof(signature),
0);
switch (status)
{
case STATUS_SUCCESS:
wprintf(L"Signature verified successfully\n");
exitCode = ERROR_SUCCESS;
break;
case STATUS_INVALID_SIGNATURE:
wprintf(L"Signature did not verify\n");
exitCode = ERROR_INVALID_DATA;
break;
default:
wprintf(L"**** Error 0x%x returned by BCryptVerifySignature\n", status);
goto Cleanup;
}
Cleanup:
if (hHash != nullptr)
BCryptDestroyHash(hHash);
if (sha256 != nullptr)
BCryptCloseAlgorithmProvider(sha256, 0);
if (importedPublicKey != nullptr)
BCryptDestroyKey(importedPublicKey);
LocalFree(subjectPublicKeyInfo);
return exitCode;
}
So, I have little problem with CM_Get_Device_Interface_List function. Function returns with error code 3, which is CR_INVALID_POINTER. But when I call CM_Get_Device_Interface_List_Size function, it returns success.
ULONG lenght = 0;
PWSTR DevicePath = NULL;
CONFIGRET cr = CR_SUCCESS;
cr = CM_Get_Device_Interface_List_Size(&lenght, (LPGUID)&HWN_DEVINTERFACE_NLED, NULL, CM_GET_DEVICE_INTERFACE_LIST_PRESENT);// success
if (cr != CR_SUCCESS)
{
// error handling
}
cr = CM_Get_Device_Interface_List((LPGUID)&HWN_DEVINTERFACE_NLED, NULL, DevicePath, lenght, CM_GET_DEVICE_INTERFACE_LIST_PRESENT); // error
if (cr != CR_SUCCESS)
{
// error handling
}
DEFINE_GUID(HWN_DEVINTERFACE_NLED,
0x6b2a25e2, 0xaaf5, 0x482c, 0x99, 0xa5, 0x62, 0x05, 0xcd, 0xcc, 0x17, 0x6a); // GUID Declaration
So, why the pointer is invalid?
A bit late, probably figured this out but in case someone else comes across this I believe the reason you are getting the invalid pointer is because you are passing in a null pointer as the buffer (DevicePath), it must be allocated with the size returned from your first call.
Example (cleaned up a bit):
ULONG bufferSize = 0;
if (CM_Get_Device_Interface_List_Size(&bufferSize, (LPGUID)&HWN_DEVINTERFACE_NLED, NULL, CM_GET_DEVICE_INTERFACE_LIST_PRESENT) == CR_SUCCESS)
{
PWSTR buffer = (PWSTR)malloc(bufferSize);
if (CM_Get_Device_Interface_List((LPGUID)&HWN_DEVINTERFACE_NLED, NULL, buffer, bufferSize, CM_GET_DEVICE_INTERFACE_LIST_PRESENT) == CR_SUCCESS)
{
// buffer should now contain a list of NULL-terminated unicode strings
}
if (buffer)
{
free(buffer);
}
}
DEFINE_GUID(HWN_DEVINTERFACE_NLED,
0x6b2a25e2, 0xaaf5, 0x482c, 0x99, 0xa5, 0x62, 0x05, 0xcd, 0xcc, 0x17, 0x6a); // GUID Declaration
Alternate Example (no malloc):
#define BUFFER_SIZE 4096 // 4k buffer should be plenty
WCHAR buffer[BUFFER_SIZE];
if (CM_Get_Device_Interface_List((LPGUID)&HWN_DEVINTERFACE_NLED, NULL, buffer, BUFFER_SIZE, CM_GET_DEVICE_INTERFACE_LIST_PRESENT) == CR_SUCCESS)
{
// buffer should now contain a list of NULL-terminated unicode strings
}
DEFINE_GUID(HWN_DEVINTERFACE_NLED,
0x6b2a25e2, 0xaaf5, 0x482c, 0x99, 0xa5, 0x62, 0x05, 0xcd, 0xcc, 0x17, 0x6a); // GUID Declaration
I am trying to decrypt something using 128BIT AES Decryption. When i attempt to calling CryptDecrypt i get an Error stating "Invalid Algorithm Specified". I get the same problem when using the library posted here: http://www.codeproject.com/KB/security/WinAES.aspx
What can cause this error?
I am using CryptoAPI along on vista64bit with visual studio 2008. I checked in the registry and the AES library is there...
EDIT
BYTE*& encryptedData /* get data length */
HCRYPTPROV cryptoHandle = NULL;
HCRYPTKEY aesKeyHandle = NULL;
hr = InitWinCrypt(cryptoHandle);
if(FAILED(hr))
{
return hr;
}
AesKeyOffering aesKey = { {PLAINTEXTKEYBLOB, CUR_BLOB_VERSION, 0, CALG_AES_128}, 16, { 0xFF, 0x00, 0xFF, 0x1C, 0x1D, 0x1E, 0x03, 0x04, 0x05, 0x0F, 0x20, 0x21, 0xAD, 0xAF, 0xA4, 0x04 }};
if(CryptImportKey(cryptoHandle, (CONST BYTE*)&aesKey, sizeof(AesKeyOffering), NULL, 0, &aesKeyHandle) == FALSE)
{
// DO error
return HRESULT_FROM_WIN32(GetLastError());
}
if(CryptSetKeyParam(aesKeyHandle, KP_IV, { 0xFF, 0x00, 0xFF, 0x1C, 0x1D, 0x1E, 0x03, 0x04, 0x05, 0x0F, 0x20, 0x21, 0xAD, 0xAF, 0xA4, 0x04 } , 0) == FALSE)
{
return HRESULT_FROM_WIN32(GetLastError());
}
BYTE blah2 = CRYPT_MODE_CBC;
// set block mode
if(CryptSetKeyParam(aesKeyHandle, KP_MODE, &blah2, 0) == FALSE)
{
//
return HRESULT_FROM_WIN32(GetLastError());
}
DWORD lol = dataLength / 16 + 1;
DWORD lol2 = lol * 16;
if(CryptDecrypt(aesKeyHandle, 0, TRUE, 0, encryptedData, &lol2) == FALSE)
{
return HRESULT_FROM_WIN32(GetLastError());
}
InitWinCrypt function
if(!CryptAcquireContextW(&cryptoHandle, NULL, L"Microsoft Enhanced RSA and AES Cryptographic Provider", PROV_RSA_AES, CRYPT_VERIFYCONTEXT))
{
if(!CryptAcquireContextW(&cryptoHandle, NULL, L"Microsoft Enhanced RSA and AES Cryptographic Provider", PROV_RSA_AES, 0))
{
return HRESULT_FROM_WIN32(GetLastError());
}
else
{
return S_OK;
}
}
return S_OK;
AesOffering struct:
struct AesKeyOffering
{
BLOBHEADER m_Header;
DWORD m_KeyLength;
BYTE Key[16];
};
EDIT2
After rebooting my computer, and remvoing the CBC chunk. I am now getting Bad Data Errors. The data decrypts fine in C#. But i need to do this using wincrypt.
Are you passing cryptoHandle by reference to InitWithCrypt? If not, your code
if(!CryptAcquireContextW(&cryptoHandle, ...
would only modify InitWinCrypt's copy of cryptoHandle.
EDIT: Given that it does, try getting rid of the CryptSetKeyParam call which sets CRYPT_MODE_CBC