I have a program that generates a hash key from a file.
For example the result of the program is "hash of file c:\Users\Jax\Desktop\files\file.txt is: 4db5a10d2ea73e3f76".
And I have a variable that has the expected hash for this file.txt:
char hashExpected = "4db5a10d2ea73e3f76";
And in a specifc part of the code I'm verifying if the result hash of the program is equal to the hash stored in the hashExpected variable. I have this like below. I have the hashResult variable storing the result hash so then I can compare. But it's not working properly because it always shows Hash is different even when it's equal. It seems that the hashResult variable is not storing the correct values.
for (i = 0; i < cbHash; i++)
{
printf("%c%c",
rgbDigits[rgbHash[i] >> 4],
rgbDigits[rgbHash[i] & 0xf]);
hashResult[i] = rgbDigits[rgbHash[i] >> 4];
hashResult[i] += rgbDigits[rgbHash[i] & 0xf];
}
if (verify(hashResult, hashExpected))
{
printf("Hash is the same\n");
}
else
{
printf("Hash is different\n");
}
Full program:
#include <stdio.h>
#include <windows.h>
#include <Wincrypt.h>
#include <stdbool.h>
#define BUFSIZE 1024
#define MD5LEN 16
bool verify(char array1[], char array2[])
{
int i;
for (i = 0; array1[i] && array2[i]; ++i)
{
if (array1[i] != array2[i])
{
return false;
}
}
return true;
}
DWORD main()
{
DWORD dwStatus = 0;
BOOL bResult = FALSE;
HCRYPTPROV hProv = 0;
HCRYPTHASH hHash = 0;
HANDLE hFile = NULL;
BYTE rgbFile[BUFSIZE];
DWORD cbRead = 0;
BYTE rgbHash[MD5LEN];
DWORD cbHash = 0;
CHAR rgbDigits[] = "0123456789abcdef";
PCSTR filename = "c:\\Users\\Jax\\Desktop\\files\\file.txt";
char hashActual[] = "4db5a10d2ea73e3f76";
char hashExpected[] = "4db5a10d2ea73e3f76";
char hashWrong[] = "0a0a0a0a0a0a0a";
char hashResult[] = "";
hFile = CreateFile(filename,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_FLAG_SEQUENTIAL_SCAN,
NULL);
if (INVALID_HANDLE_VALUE == hFile)
{
dwStatus = GetLastError();
printf("Error opening file %s\nError: %d\n", filename,
dwStatus);
return dwStatus;
}
// Get handle to the crypto provider
if (!CryptAcquireContext(&hProv,
NULL,
NULL,
PROV_RSA_FULL,
CRYPT_VERIFYCONTEXT))
{
dwStatus = GetLastError();
printf("CryptAcquireContext failed: %d\n", dwStatus);
CloseHandle(hFile);
return dwStatus;
}
if (!CryptCreateHash(hProv, CALG_MD5, 0, 0, &hHash))
{
dwStatus = GetLastError();
printf("CryptAcquireContext failed: %d\n", dwStatus);
CloseHandle(hFile);
CryptReleaseContext(hProv, 0);
return dwStatus;
}
while (bResult = ReadFile(hFile, rgbFile, BUFSIZE,
&cbRead, NULL))
{
if (0 == cbRead)
{
break;
}
if (!CryptHashData(hHash, rgbFile, cbRead, 0))
{
dwStatus = GetLastError();
printf("CryptHashData failed: %d\n", dwStatus);
CryptReleaseContext(hProv, 0);
CryptDestroyHash(hHash);
CloseHandle(hFile);
return dwStatus;
}
}
if (!bResult)
{
dwStatus = GetLastError();
printf("ReadFile failed: %d\n", dwStatus);
CryptReleaseContext(hProv, 0);
CryptDestroyHash(hHash);
CloseHandle(hFile);
return dwStatus;
}
cbHash = MD5LEN;
if (CryptGetHashParam(hHash, HP_HASHVAL, rgbHash, &cbHash, 0))
{
DWORD i;
printf("MD5 hash of file %s is: ", filename);
for (i = 0; i < cbHash; i++)
{
printf("%c%c",
rgbDigits[rgbHash[i] >> 4],
rgbDigits[rgbHash[i] & 0xf]);
hashResult[i] = rgbDigits[rgbHash[i] >> 4];
hashResult[i] += rgbDigits[rgbHash[i] & 0xf];
}
if (verify(hashResult, hashExpected))
{
printf("Hash is the same\n");
}
else
{
printf("Hash is different\n");
}
}
else
{
dwStatus = GetLastError();
printf("CryptGetHashParam failed: %d\n", dwStatus);
}
CryptDestroyHash(hHash);
CryptReleaseContext(hProv, 0);
CloseHandle(hFile);
return dwStatus;
}
char hashExpected[] = "4db5a10d2ea73e3f76";
Above MD5 value is wrong. MD5 values are 16 bytes long. But that's just for the bytes. We cannot print bytes on the screen, so often times we convert bytes to hexadecimal values. For example, if we have unsinged char bytes[3] = {0x01,0x01,0xFF}, we convert bytes to hexadecimal string, it becomes "0102FF".
Note that the string representation is twice longer plus a nul-terminator. Example of MD5 hash is:
"C4CA4238A0B923820DCC509A6F75849B"
The buffer size for the string should be 33 (16 x 2 + 1)
To find the correct hashExpected, search for "Online MD5 calculator". You can use a website like http://onlinemd5.com/ to calculate the MD5 of file.
Or use a file whose content is 1. MD5("1") is "C4CA4238A0B923820DCC509A6F75849B", use that as expected hash value.
char hashResult[] = "";
Above line is a programming error, as mentioned in comments by #melpomene
hashResult[i] = rgbDigits[rgbHash[i] >> 4];
hashResult[i] += rgbDigits[rgbHash[i] & 0xf];
Above code is wrong, you want this instead:
char hashResult[MD5LEN * 2 + 1] = "";
...
hashResult[i * 2] = rgbDigits[rgbHash[i] >> 4];
hashResult[i * 2 + 1] = rgbDigits[rgbHash[i] & 0xf];
Also there is a problem with the function verify because it is comparing the wrong MD5 in byte representation with the wrong MD5 in string representation.
You can use strcmp or _stricmp to compare MD5 values in string representation. Or use memcmp(data1, data2, 16) to compare bytes directly.
Full example:
#define BUFSIZE 1024
#define MD5LEN 16
int main()
{
DWORD dwStatus = 0;
HCRYPTPROV hProv = 0;
HCRYPTHASH hHash = 0;
HANDLE hFile = NULL;
BYTE rgbFile[BUFSIZE];
DWORD cbRead = 0;
BYTE rgbHash[MD5LEN];
DWORD cbHash = 0;
CHAR rgbDigits[] = "0123456789abcdef";
PCSTR filename = "c:\\Users\\Jax\\Desktop\\files\\file.txt";
//assuming content of file.txt is '1'
char hashExpected[] = "C4CA4238A0B923820DCC509A6F75849B";
char hashResult[MD5LEN * 2 + 1] = "";
hFile = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ,
NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
if(INVALID_HANDLE_VALUE == hFile)
{
dwStatus = GetLastError();
printf("Error opening file %s\nError: %d\n", filename, dwStatus);
return (int)dwStatus;
}
// Get handle to the crypto provider
if(!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
{
dwStatus = GetLastError();
printf("CryptAcquireContext failed: %d\n", dwStatus);
CloseHandle(hFile);
return (int)dwStatus;
}
if(!CryptCreateHash(hProv, CALG_MD5, 0, 0, &hHash))
{
dwStatus = GetLastError();
printf("CryptAcquireContext failed: %d\n", dwStatus);
CloseHandle(hFile);
CryptReleaseContext(hProv, 0);
return (int)dwStatus;
}
while(ReadFile(hFile, rgbFile, BUFSIZE, &cbRead, NULL))
{
if(0 == cbRead)
break;
if(!CryptHashData(hHash, rgbFile, cbRead, 0))
{
dwStatus = GetLastError();
printf("CryptHashData failed: %d\n", dwStatus);
CryptReleaseContext(hProv, 0);
CryptDestroyHash(hHash);
CloseHandle(hFile);
return (int)dwStatus;
}
}
cbHash = MD5LEN;
if(CryptGetHashParam(hHash, HP_HASHVAL, rgbHash, &cbHash, 0))
{
DWORD i;
printf("MD5 expected, versus MD5 of file %s is:\n", filename);
printf("%s\n", hashExpected);
for(i = 0; i < cbHash; i++)
{
printf("%c%c",
rgbDigits[rgbHash[i] >> 4],
rgbDigits[rgbHash[i] & 0xf]);
hashResult[i * 2] = rgbDigits[rgbHash[i] >> 4];
hashResult[i * 2 + 1] = rgbDigits[rgbHash[i] & 0xf];
}
printf("\n");
if(_strcmpi(hashResult, hashExpected) == 0)
printf("Hash is the same\n");
else
printf("Hash is different\n");
}
else
{
dwStatus = GetLastError();
printf("CryptGetHashParam failed: %d\n", dwStatus);
}
CryptDestroyHash(hHash);
CryptReleaseContext(hProv, 0);
CloseHandle(hFile);
return (int)dwStatus;
}
Related
I have a small program that is encrypting files using the AES-256 key. The key used to encrypt the file is generated randomly.
The encryption program goes like this:
Acquire crypto context - CryptAcquireContext
generate an AES-256 key using CryptGenKey
Encrypt a file using this key -- CryptEncrypt
Release cryto context -- CryptReleaseContext
The file encrypted is a small test.txt file containing the string: "just a test". And so the raw hex bytes in the file are:
6A 75 73 74 20 61 20 74 65 73 74
The AES-256 key used for encryption in hex format is:
3f10e23bb1a5dfd9c8ca06195e43043386a9ba4c63c35ac518f463ba768f001b
The encrypted file test.enc then has the bytes:
C8 B5 92 51 22 53 75 A1 34 80 EC AA 37 1C 6C BE
Question:
How do I write a c/c++ program to decrypt these bytes using the hex AES-256 key using the Windows CryptoAPI's CryptDecrypt function?
What I have tried:
I have written the following decryption program (a slight modification of the gist here.)
#include <Windows.h>
#include <wincrypt.h>
#include <stdio.h>
#pragma comment(lib, "crypt32.lib")
#define BLOCK_LEN 128
HCRYPTPROV hCryptProv;
int wmain(int argc, wchar_t* argv[])
{
wchar_t default_key[] = L"PxDiO7Gl39nIygYZXkMEM4apukxjw1rFGPRjunaPABs";
wchar_t* key_str = default_key;
size_t len = lstrlenW(key_str);
if (!CryptAcquireContext(
&hCryptProv,
NULL,
MS_ENH_RSA_AES_PROV,
PROV_RSA_AES,
NULL))
{
/*std::cout << "error acquiring context\n";
std::cout << GetLastErrorAsString();*/
exit(1);
}
HCRYPTKEY hKey;
wchar_t* filename = argv[1];
wchar_t* filename2 = argv[2];
printf("Key: %S\n", key_str);
printf("Key len: %#x\n", len);
printf("Input File: %S\n", filename);
printf("Output File: %S\n", filename2);
printf("----\n");
HANDLE hInpFile = CreateFileW(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
if (hInpFile == INVALID_HANDLE_VALUE) {
printf("Cannot open input file!\n");
system("pause");
return (-1);
}
printf("\nEncrypted file read.");
HANDLE hOutFile = CreateFileW(filename2, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hOutFile == INVALID_HANDLE_VALUE) {
printf("Cannot open output file!\n");
system("pause");
return (-1);
}
printf("\nDecryption file created.");
DWORD dwStatus = 0;
BOOL bResult = FALSE;
wchar_t info[] = L"Microsoft Enhanced RSA and AES Cryptographic Provider";
/*BOOL CryptDeriveKey(
HCRYPTPROV hProv,
ALG_ID Algid,
HCRYPTHASH hBaseData,
DWORD dwFlags,
HCRYPTKEY * phKey
);*/
HCRYPTHASH hHash;
if (!CryptCreateHash(hCryptProv, CALG_SHA_256, 0, 0, &hHash)) {
dwStatus = GetLastError();
printf("CryptCreateHash failed: %x\n", dwStatus);
CryptReleaseContext(hCryptProv, 0);
system("pause");
return dwStatus;
}
if (!CryptHashData(hHash, (BYTE*)key_str, len, 0)) {
DWORD err = GetLastError();
printf("CryptHashData Failed : %#x\n", err);
system("pause");
return (-1);
}
printf("[+] CryptHashData Success\n");
if (!CryptDeriveKey(hCryptProv, CALG_AES_256, hHash, 0, &hKey)) {
dwStatus = GetLastError();
printf("CryptDeriveKey failed: %x\n", dwStatus);
CryptReleaseContext(hCryptProv, 0);
system("pause");
return dwStatus;
}
printf("[+] CryptDeriveKey Success\n");
const size_t chunk_size = BLOCK_LEN;
BYTE chunk[chunk_size] = { 0 };
DWORD out_len = 0;
BOOL isFinal = FALSE;
DWORD readTotalSize = 0;
DWORD inputSize = GetFileSize(hInpFile, NULL);
while (bResult = ReadFile(hInpFile, chunk, chunk_size, &out_len, NULL)) {
if (0 == out_len) {
break;
}
printf("\nFile read.");
readTotalSize += out_len;
if (readTotalSize == inputSize) {
isFinal = TRUE;
printf("\nFinal chunk set.\n");
}
printf("\n Now calling decryption routine...");
if (!CryptDecrypt(hKey, NULL, isFinal, 0, chunk, &out_len)) {
printf("[-] CryptDecrypt failed\n");
break;
}
printf("CryptDecrypt succeeded.");
DWORD written = 0;
if (!WriteFile(hOutFile, chunk, out_len, &written, NULL)) {
printf("writing failed!\n");
break;
}
memset(chunk, 0, chunk_size);
}
CryptReleaseContext(hCryptProv, 0);
CryptDestroyKey(hKey);
CryptDestroyHash(hHash);
CloseHandle(hInpFile);
CloseHandle(hOutFile);
printf("Finished. Processed %#x bytes.\n", readTotalSize);
system("pause");
return 0;
}
This just ends up telling me CryptDecrypt failed. So I'm guessing the key wasn't specified in the right format. I do not know how to use my AES-256 key in hex format to decrypt the data. The key is currently hard-coded in a base64 format in the program but I'm guessing that's not correct.
Another thing I have done is that I have used the CryptoTester tool to specify the AES key that I have in hex format and it is able to actually successfully decrypt the file. Also, this online decryption tool is also able to use the key to decrypt the data as shown here. So I know that I have the right hex key and everything and that the file can decrypted, but how do I rewrite my program above to correctly decrypt the file?
Note that all keys used or shown here are just examples.
How do I correct this program to actually decrypt the data successfully using the AES-256 key above?
Simple Demo Program
Here is a small C program that uses your key and the encrypted data supplied with it and decrypts the original text again. I have tried to make it minimalistic.
For the sake of simplicity, it does not read the files from the file system, but defines the data in the C program as hex strings.
Result
When you run the program, the following output is output to the console:
decrypted result: 'just a test'
C Code
#include <stdio.h>
#include <windows.h>
#include <wincrypt.h>
void error(const char* what) {
fprintf(stderr, "%s failed with last error 0x%x\n", what, GetLastError());
exit(1);
}
#define AES_KEY_SIZE 32
typedef struct {
BLOBHEADER hdr;
DWORD dwKeySize;
BYTE rgbKeyData[AES_KEY_SIZE];
} AES256KEYBLOB;
BYTE *hex2byte(const char *hex) {
int len = strlen(hex) / 2;
BYTE* bytes = malloc(len);
if (bytes == NULL) {
error("malloc");
return NULL;
}
unsigned char val[2];
for (int i = 0; i < len; i++) {
sscanf_s(&hex[i * 2], "%2hhx", &val);
bytes[i] = val[0];
}
return bytes;
}
int main() {
BYTE *key = hex2byte("3F10E23BB1A5DFD9C8CA06195E43043386A9BA4C63C35AC518F463BA768F001B");
AES256KEYBLOB aes256KeyBlob;
aes256KeyBlob.hdr.bType = PLAINTEXTKEYBLOB;
aes256KeyBlob.hdr.bVersion = CUR_BLOB_VERSION;
aes256KeyBlob.hdr.reserved = 0;
aes256KeyBlob.hdr.aiKeyAlg = CALG_AES_256;
aes256KeyBlob.dwKeySize = AES_KEY_SIZE;
memcpy(aes256KeyBlob.rgbKeyData, key, AES_KEY_SIZE);
HCRYPTPROV hProv;
if (!CryptAcquireContextA(&hProv, NULL, MS_ENH_RSA_AES_PROV_A, PROV_RSA_AES, CRYPT_VERIFYCONTEXT)) {
error("CryptAcquireContext");
}
HCRYPTKEY hKey;
if (!CryptImportKey(hProv, (BYTE*)& aes256KeyBlob, sizeof(AES256KEYBLOB), 0, CRYPT_EXPORTABLE, &hKey)) {
CryptReleaseContext(hProv, 0);
error("CryptImportKey");
}
const char *encodedHex = "C8B59251225375A13480ECAA371C6CBE";
DWORD numBytes = strlen(encodedHex) / 2;
BYTE *encoded = hex2byte(encodedHex);
if (CryptDecrypt(hKey, 0, TRUE, 0, encoded, &numBytes)) {
printf("decrypted result: '");
for (DWORD i = 0; i < numBytes; i++) {
printf("%c", encoded[i]);
}
printf("'\n");
} else {
CryptDestroyKey(hKey);
CryptReleaseContext(hProv, 0);
error("CryptDecrypt");
}
free(key);
free(encoded);
CryptDestroyKey(hKey);
CryptReleaseContext(hProv, 0);
return 0;
}
Microsoft Docs
The KEYBLOB struct is documented here:
https://learn.microsoft.com/en-us/previous-versions/windows/desktop/legacy/jj650836(v%3Dvs.85)
whereas here you will find information about the BLOBHEADER structure:
https://learn.microsoft.com/en-us/windows/desktop/api/wincrypt/ns-wincrypt-publickeystruc
I am trying to concurrently read a file at different offsets. I am able to do so using pread in posix systems, but I can't figure out how to do it using ReadFile for windows systems. I'm having difficulty understanding a lot of the Windows documentation. Can anyone show me an example of how I should be using ReadFile instead?
EDIT See working code here!
do {
#ifdef _WIN32
OVERLAPPED overlapped;
memset(&overlapped, 0, sizeof(OVERLAPPED));
overlapped.Offset = shard_meta->index*state->shard_size + total_read;
HANDLE file = (HANDLE)_get_osfhandle(fileno(state->original_file));
SetLastError(0);
bool RF = ReadFile(file, read_data, AES_BLOCK_SIZE * 256, NULL, &overlapped);
if ((RF==0) && GetLastError() == ERROR_IO_PENDING) {
printf ("Asynch readfile started. I can do other operations now\n");
while( !GetOverlappedResult(file, &overlapped, &read_bytes, TRUE)) {
if (GetLastError() == ERROR_IO_INCOMPLETE) {
printf("I/O pending: %d .\n",GetLastError());
} else if (GetLastError() == ERROR_HANDLE_EOF) {
printf("End of file reached.\n");
break;
} else {
printf("GetOverlappedResult failed with error:%d\n",GetLastError());
break;
}
}
} else if ((RF == 0) && GetLastError() != ERROR_IO_PENDING) {
printf ("Error reading file :%d\n",GetLastError());
goto clean_variables;
}
#else
read_bytes = pread(fileno(state->original_file),
read_data, AES_BLOCK_SIZE * 256,
shard_meta->index*state->shard_size + total_read);
#endif
total_read += read_bytes;
memset_zero(read_data, AES_BLOCK_SIZE * 256);
} while(total_read < state->shard_size && read_bytes > 0);
See working code below
#ifdef _WIN32
ssize_t pread(int fd, void *buf, size_t count, uint64_t offset)
{
long unsigned int read_bytes = 0;
OVERLAPPED overlapped;
memset(&overlapped, 0, sizeof(OVERLAPPED));
overlapped.OffsetHigh = (uint32_t)((offset & 0xFFFFFFFF00000000LL) >> 32);
overlapped.Offset = (uint32_t)(offset & 0xFFFFFFFFLL);
HANDLE file = (HANDLE)_get_osfhandle(fd);
SetLastError(0);
bool RF = ReadFile(file, buf, count, &read_bytes, &overlapped);
// For some reason it errors when it hits end of file so we don't want to check that
if ((RF == 0) && GetLastError() != ERROR_HANDLE_EOF) {
errno = GetLastError();
// printf ("Error reading file : %d\n", GetLastError());
return -1;
}
return read_bytes;
}
ssize_t pwrite(int fd, const void *buf, size_t count, uint64_t offset)
{
long unsigned int written_bytes = 0;
OVERLAPPED overlapped;
memset(&overlapped, 0, sizeof(OVERLAPPED));
overlapped.OffsetHigh = (uint32_t)((offset & 0xFFFFFFFF00000000LL) >> 32);
overlapped.Offset = (uint32_t)(offset & 0xFFFFFFFFLL);
HANDLE file = (HANDLE)_get_osfhandle(fd);
SetLastError(0);
bool RF = WriteFile(file, buf, count, &written_bytes, &overlapped);
if ((RF == 0)) {
errno = GetLastError();
// printf ("Error reading file :%d\n", GetLastError());
return -1;
}
return written_bytes;
}
#endif
I have a program that generates a hash key from a file. And also verifies if the result hash is equal to the expected hash. But the program is just working for one file each time. Now, I was trying to generate a hash key from each file in a given directory and do the comparison with each expected hash.
For that I have the code below to read the directory. But I am not having success to associate the expected hash to each file that I have in the directory.
With strcmp I can compare and it is already working, but then how can I associate the correct expected hash with the corresponding file? Do you know how to do that?
PCSTR text = "C:\\Users\\Jax\\Desktop\\files\\files2\\txt_1.txt";
PCSTR pptx = "C:\\Users\\Jax\\Desktop\\files\\files2\\Test.pptx";
DIR *d;
d = opendir("C:\\Users\\Jax\\Desktop\\files\\files2\\");
struct dirent *dir;
char name[256][256];
int count = 0;
int index = 0;
char TextExpected[] = "811676652bf08c0a91a849d66bb2a46c";
char PptxExpected[] = "b011367338c3264f1f3f74107060d788";
while ((dir = readdir(d)) != NULL)
{
printf("%s\n", dir->d_name);
strcpy(name[count],dir->d_name);
count++;
if(strcmp(dir->d_name,"test.pptx") == 0){
// how can I do here to associate the hashExpected to the file "test.pptx"
}
if(strcmp(dir->d_name,"test.txt") == 0){
// how can I do here to associate the hashExpected to the file "test.txt"
}
}
closedir(d);
while( count > 0 )
{
...
Inside the while ( count > 0) I execute the code to generate the hash key for each file in the directory(count > 0).
This is the complete program, it is working just that associating part I am not having success in getting it to work:
#include <stdio.h>
#include <windows.h>
#include <Wincrypt.h>
#include <dirent.h>
#include <stdbool.h>
#define BUFSIZE 1024
#define MD5LEN 16
int main()
{
DWORD dwStatus = 0;
HCRYPTPROV hProv = 0;
HCRYPTHASH hHash = 0;
HANDLE hFile = NULL;
BYTE rgbFile[BUFSIZE];
DWORD cbRead = 0;
BYTE rgbHash[MD5LEN];
DWORD cbHash = 0;
CHAR rgbDigits[] = "0123456789abcdef";
PCSTR text = "C:\\Users\\Jax\\Desktop\\files\\files2\\txt_1.txt";
PCSTR pptx = "C:\\Users\\Jax\\Desktop\\files\\files2\\Test.pptx";
DIR *d;
d = opendir("C:\\Users\\Jax\\Desktop\\files\\files2\\");
struct dirent *dir;
struct dirent *test;
char name[256][256];
int count = 0;
int index = 0;
int expected[25];
int countcount;
char testtest[256][256];
char TextExpected[] = "811676652bf08c0a91a849d66bb2a46c";
char PptxExpected[] = "b011367338c3264f1f3f74107060d788";
while ((dir = readdir(d)) != NULL)
{
printf("%s\n", dir->d_name);
strcpy(name[count],dir->d_name);
count++;
if(strcmp(dir->d_name,"test.pptx") == 0){
// how can I do here to associate the hashExpected to the file "test.pptx"
}
if(strcmp(dir->d_name,"test.txt") == 0){
// how can I do here to associate the hashExpected to the file "test.txt"
}
}
closedir(d);
while( count > 0 )
{
bool incorrect = FALSE;
char hashResult[MD5LEN * 2 + 1] = "";
hFile = CreateFile(text, GENERIC_READ, FILE_SHARE_READ,
NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
if(INVALID_HANDLE_VALUE == hFile)
{
incorrect = TRUE;
dwStatus = GetLastError();
printf("Error opening file %s\nError: %d\n", text, dwStatus);
return (int)dwStatus;
}
// Get handle to the crypto provider
if(!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
{
dwStatus = GetLastError();
printf("CryptAcquireContext failed: %d\n", dwStatus);
CloseHandle(hFile);
return (int)dwStatus;
}
if(!CryptCreateHash(hProv, CALG_MD5, 0, 0, &hHash))
{
dwStatus = GetLastError();
printf("CryptAcquireContext failed: %d\n", dwStatus);
CloseHandle(hFile);
CryptReleaseContext(hProv, 0);
return (int)dwStatus;
}
while(ReadFile(hFile, rgbFile, BUFSIZE, &cbRead, NULL))
{
if(0 == cbRead)
break;
if(!CryptHashData(hHash, rgbFile, cbRead, 0))
{
dwStatus = GetLastError();
printf("CryptHashData failed: %d\n", dwStatus);
CryptReleaseContext(hProv, 0);
CryptDestroyHash(hHash);
CloseHandle(hFile);
return (int)dwStatus;
}
}
cbHash = MD5LEN;
if(CryptGetHashParam(hHash, HP_HASHVAL, rgbHash, &cbHash, 0))
{
DWORD i;
printf("MD5 expected, versus MD5 of file %s is:\n", text);
printf("%s\n", TextExpected);
for(i = 0; i < cbHash; i++)
{
printf("%c%c",
rgbDigits[rgbHash[i] >> 4],
rgbDigits[rgbHash[i] & 0xf]);
hashResult[i * 2] = rgbDigits[rgbHash[i] >> 4];
hashResult[i * 2 + 1] = rgbDigits[rgbHash[i] & 0xf];
}
printf("\n");
if(_strcmpi(hashResult, TextExpected) == 0)
printf("Hash is the same\n");
else
printf("Hash is different\n");
}
else
{
dwStatus = GetLastError();
printf("CryptGetHashParam failed: %d\n", dwStatus);
}
CryptDestroyHash(hHash);
CryptReleaseContext(hProv, 0);
CloseHandle(hFile);
return (int)dwStatus;
}
}
strcpy(name[count],dir->d_name);
d_name is relative filename, for example "test.txt", but most likely you want to use full path name for crypt functions. Use full path instead. Example:
strcpy(name[count],"c:\\dir\\");
strcat(name[count],dir->d_name);
readdir's result includes "." and ".." which are basically useless, you want to skip them:
if(strcmp(dir->d_name,".") == 0 || strcmp(dir->d_name,"..") == 0)
continue;
while( count > 0 ) puts the code in infinite loop. You mean to do this instead:
int index = 0;
while( index < count )
{
const char* filename = name[index];
index++;
}
Note, you want to use name[index] and not name. You probably don't want to exit the loop whenever error occurs, instead you want to continue.
Finally, add a function which will look up the expect hash value for known files. Example:
#include <stdio.h>
#include <windows.h>
#include <Wincrypt.h>
#include <dirent.h>
#include <stdbool.h>
#define BUFSIZE 1024
#define MD5LEN 16
const char* get_expected_hash(const char* filename)
{
PCSTR text = "C:\\Users\\Jax\\Desktop\\files\\files2\\txt_1.txt";
PCSTR pptx = "C:\\Users\\Jax\\Desktop\\files\\files2\\Test.pptx";
const char* TextExpected = "811676652bf08c0a91a849d66bb2a46c";
const char* PptxExpected = "b011367338c3264f1f3f74107060d788";
if (stricmp(filename, text) == 0)
return TextExpected;
if (stricmp(filename, pptx) == 0)
return PptxExpected;
return "unknown hash";
}
int main()
{
DWORD dwStatus = 0;
HCRYPTPROV hProv = 0;
HCRYPTHASH hHash = 0;
HANDLE hFile = NULL;
BYTE rgbFile[BUFSIZE];
DWORD cbRead = 0;
BYTE rgbHash[MD5LEN];
DWORD cbHash = 0;
CHAR rgbDigits[] = "0123456789abcdef";
//const char* dirname = "C:\\Users\\Jax\\Desktop\\files\\files2\\";
const char* dirname = "c:\\test\\";
DIR *d;
d = opendir(dirname);
struct dirent *dir;
char files[256][256];
int count = 0;
while ((dir = readdir(d)) != NULL)
{
if(strcmp(dir->d_name,".") == 0 || strcmp(dir->d_name,"..") == 0)
continue;
strcpy(files[count],dirname);
strcat(files[count],dir->d_name);
count++;
}
closedir(d);
// Get handle to the crypto provider
if(!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
{
dwStatus = GetLastError();
printf("CryptAcquireContext failed: %d\n", (int)dwStatus);
CloseHandle(hFile);
return (int)dwStatus;
}
int index = 0;
while( index < count )
{
const char* filename = files[index];
index++;
printf("%s\n", filename);
char hashResult[MD5LEN * 2 + 1] = "";
hFile = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ,
NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
if(INVALID_HANDLE_VALUE == hFile)
{
//incorrect = TRUE;
dwStatus = GetLastError();
printf("Error opening file %s\nError: %d\n", filename, (int)dwStatus);
return (int)dwStatus;
}
if(!CryptCreateHash(hProv, CALG_MD5, 0, 0, &hHash))
{
dwStatus = GetLastError();
printf("CryptAcquireContext failed: %d\n", (int)dwStatus);
CloseHandle(hFile);
CryptReleaseContext(hProv, 0);
continue;
}
while(ReadFile(hFile, rgbFile, BUFSIZE, &cbRead, NULL))
{
if(0 == cbRead)
break;
if(!CryptHashData(hHash, rgbFile, cbRead, 0))
{
dwStatus = GetLastError();
printf("CryptHashData failed: %d\n", (int)dwStatus);
CryptReleaseContext(hProv, 0);
CryptDestroyHash(hHash);
CloseHandle(hFile);
continue;
}
}
cbHash = MD5LEN;
if(CryptGetHashParam(hHash, HP_HASHVAL, rgbHash, &cbHash, 0))
{
DWORD i;
printf("MD5 expected, versus MD5 of file %s is:\n", filename);
const char* TextExpected = get_expected_hash(filename);
printf("%s\n", TextExpected);
for(i = 0; i < cbHash; i++)
{
printf("%c%c", rgbDigits[rgbHash[i] >> 4], rgbDigits[rgbHash[i] & 0xf]);
hashResult[i * 2] = rgbDigits[rgbHash[i] >> 4];
hashResult[i * 2 + 1] = rgbDigits[rgbHash[i] & 0xf];
}
//printf("\n");
if(_strcmpi(hashResult, TextExpected) == 0)
printf("Hash is the same\n");
else
printf("Hash is different\n");
}
else
{
dwStatus = GetLastError();
printf("CryptGetHashParam failed: %d\n", (int)dwStatus);
continue;
}
CryptDestroyHash(hHash);
CloseHandle(hFile);
}
CryptReleaseContext(hProv, 0);
return 0;
}
I want to send and receive data from device to pc and vice versa. I am sending the string, but not able to receive it fully. Example: Sent string is Hello, and the output is:
Received:H
Error in read! e = -4 and received = 5
#include <string.h>
#include<stdio.h>
#include <stdlib.h>
#include <libusb-1.0/libusb.h>
#define BULK_EP_OUT 0x01
#define BULK_EP_IN 0x81
/*find these values using lsusb -v*/
uint16_t VENDOR = 0x0483;
uint16_t PRODUCT = 0x5740;
int main(void)
{
int ret = 1; //int type result
struct libusb_device **usb_dev;
struct libusb_device_descriptor desc;
struct libusb_device_handle *handle = NULL;
struct device_handle_expected;
//struct libusb_device_handle device_expected_handle = NULL;
struct libusb_device *dev, *dev_expected;
char *my_string, *my_string1;
int e = 0, config;
char found = 0;
int transferred = 0;
int received = 0;
int length = 0;
int i=0;
int count;
/*struct libusb_device *dev;
struct libusb_device **devs;
struct dev_expected;*/
// Initialize libusb
ret = libusb_init(NULL);
if(ret < 0)
{
printf("\nFailed to initialise libusb\n");
return 1;
}
else
printf("\nInit successful!\n");
// Get a list of USB devices
count = libusb_get_device_list(NULL, &usb_dev);
if (count < 0)
{
printf("\nThere are no USB devices on the bus\n");
return -1;
}
printf("\nToally we have %d devices\n", count);
while ((dev = usb_dev[i++]) != NULL)
{
ret = libusb_get_device_descriptor(dev, &desc);
if (ret < 0)
{
printf("Failed to get device descriptor\n");
libusb_free_device_list(dev, 1);
break;
}
e = libusb_open(dev, &handle);
if (e < 0)
{
printf("Error opening device\n");
libusb_free_device_list(dev, 1);
libusb_close(handle);
break;
}
if(desc.idVendor == 0x0483 && desc.idProduct == 0x5740)
{
found = 1;
break;
}
}//end of while
if(found == 0)
{
printf("\nDevice NOT found\n");
libusb_free_device_list(usb_dev, 1);
libusb_close(handle);
return 1;
}
else
{
printf("\nDevice found");
// dev_expected = dev;
//device_handle_expected = handle;
}
e = libusb_get_configuration(handle, &config);
if(e!=0)
{
printf("\n***Error in libusb_get_configuration\n");
libusb_free_device_list(usb_dev, 1);
libusb_close(handle);
return -1;
}
printf("\nConfigured value: %d", config);
if(config != 1)
{
libusb_set_configuration(handle, 1);
if(e!=0)
{
printf("Error in libusb_set_configuration\n");
libusb_free_device_list(usb_dev, 1);
libusb_close(handle);
return -1;
}
else
printf("\nDevice is in configured state!");
}
if(libusb_kernel_driver_active(handle, 0) == 1)
{
printf("\nKernel Driver Active");
if(libusb_detach_kernel_driver(handle, 0) == 0)
printf("\nKernel Driver Detached!");
else
{
printf("\nCouldn't detach kernel driver!\n");
libusb_free_device_list(usb_dev, 1);
libusb_close(handle);
return -1;
}
}
e = libusb_claim_interface(handle, 0);
if(e < 0)
{
printf("\nCannot Claim Interface");
libusb_free_device_list(usb_dev, 1);
libusb_close(handle);
return -1;
}
else
printf("\nClaimed Interface\n");
int nbytes = 64;
my_string = (char *) malloc(nbytes + 1);
my_string1 = (char *) malloc(nbytes + 1);
memset(my_string, '\0', 64);//The C library function void (an unsigned char) to the first n characters of the string pointed to, by the argument str.
memset(my_string1, '\0', 64);
strcpy(my_string, "Hello");
length = strlen(my_string);
printf("\nTo be sent: %s", my_string);
e = libusb_bulk_transfer(handle, BULK_EP_OUT, my_string, length, &transferred, 0);
if(e == 0 && transferred == length)
{
printf("\nWrite successful!");
printf("\nSent %d bytes with string: %s\n", transferred, my_string);
}
else
printf("\nError in write! e = %d and transferred = %d\n", e, transferred);
// sleep(3);
i = 0;
for(i = 0; i <= length; i++)
{
e = libusb_bulk_transfer(handle, BULK_EP_IN, my_string1,length, &received, 0); //64: Max Packet Length
if(e == 0 && received == length)
{
printf("\nReceived:");
printf("%c", my_string1[i]);
sleep(5);
}
else
{
printf("\nError in read! e = %d and received = %d bytes\n", e, received);
return -1;
}
}
libusb_release_interface(handle, 0);
libusb_free_device_list(usb_dev, 1);
libusb_close(handle);
libusb_exit(NULL);
printf("\n");
return 0;
}
Pretty certain the bulk in transfer will transfer the entire buffer at once(up to 64--or 512 if you're doing high speed--bytes), not a byte at a time.
You're iterating over the size of the expected buffer and doing a bulk in for each byte, and only printing out the first byte.
Get rid of the for loop on the read and change your printf() to be printf("%s\n",my_string1);
I'm attempting to use the Microsoft crypto APIs to compute an MD5 hash, but I'm getting incorrect hashes:
#include <windows.h>
#include <stdio.h>
#include <wincrypt.h>
char* HashMD5(char* data, DWORD *result)
{
DWORD dwStatus = 0;
DWORD cbHash = 16;
int i = 0;
HCRYPTPROV cryptProv;
HCRYPTHASH cryptHash;
BYTE hash[16];
char *hex = "01234567879abcdef";
char *strHash = "00000000000000000000000000000000";
if(!CryptAcquireContext(&cryptProv, NULL, MS_DEF_PROV, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
{
dwStatus = GetLastError();
printf("CryptAcquireContext failed: %d\n", dwStatus);
*result = dwStatus;
return NULL;
}
if(!CryptCreateHash(cryptProv, CALG_MD5, 0, 0, &cryptHash))
{
dwStatus = GetLastError();
printf("CryptCreateHash failed: %d\n", dwStatus);
CryptReleaseContext(cryptProv, 0);
*result = dwStatus;
return NULL;
}
if(!CryptHashData(cryptHash, (BYTE*)data, strlen(data), 0))
{
dwStatus = GetLastError();
printf("CryptHashData failed: %d\n", dwStatus);
CryptReleaseContext(cryptProv, 0);
CryptDestroyHash(cryptHash);
*result = dwStatus;
return NULL;
}
if(!CryptGetHashParam(cryptHash, HP_HASHVAL, hash, &cbHash, 0))
{
dwStatus = GetLastError();
printf("CryptGetHashParam failed: %d\n", dwStatus);
CryptReleaseContext(cryptProv, 0);
CryptDestroyHash(cryptHash);
*result = dwStatus;
return NULL;
}
for(i = 0; i < cbHash; i++)
{
strHash[i*2] = hex[hash[i] >> 4];
strHash[(i*2)+1] = hex[hash[i] & 0xF];
}
CryptReleaseContext(cryptProv, 0);
CryptDestroyHash(cryptHash);
return strHash;
}
int main(int argc, char **argv)
{
DWORD result = 0;
char* hash;
if(argc != 2)
{
printf("Usage: crypto.exe <word>\n");
return 0;
}
hash = HashMD5(argv[1], &result);
if(result == 0)
{
printf("Hash of '%s' is: %s\n", argv[1], hash);
}
else
{
printf("Failed! Result: %d\n", result);
}
return result;
}
The code executes fine, no error message is printed, but the returned hash value is incorrect for certain plaintexts:
$ ./crypto.exe test
Hash of 'test' is: 078e6abc4621c373b9cd4d832627a4e6
$ ./crypto.exe StackOverflow
Hash of 'StackOverflow' is: 84c7cb17766b446e5d4084d8ebd87e82
The latter is correct, but the former should be 098f6bcd4621d373cade4e832627b4f6.
What am I doing wrong?
char *hex = "01234567879abcdef";
You have an error in that line.
It should read:
char *hex = "0123456789abcdef";
strHash[i*2] = hex[hash[i] >> 4];
strHash[(i*2)+1] = hex[hash[i] & 0xF];
strHash points to a string literal. string literal are non-modifiable. Modifying a string literal is undefined behavior.