1

I write BYTE* to bytea field in postgres with function, which returns bytea:

...
PG_RETURN_BYTEA_P(pbBuffer);

These bytes look in file like: enter image description here Later Im trying read this bytea field and write to other file with other function like this:

bytea* data = PG_GETARG_BYTEA_P(0);   
char filePath[] = "C:\\pg\\11.txt";
HANDLE h = CreateFile(filePath, FILE_WRITE_DATA, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
DWORD dw = sizeof(data);
WriteFile(h, data, dw, &dw, NULL);
CloseHandle(h);

In file It looks like: enter image description here What should I do to get the same result as in begin?

first function works:

    FILE* log = AllocateFile("C:\\pg\\log.txt", PG_BINARY_A);

char* dataToEncrypt = PG_GETARG_CSTRING(0);

FILE* tempFile = AllocateFile("C:\\pg\\openText.txt", PG_BINARY_A);
fprintf(tempFile, "%s", dataToEncrypt);
FreeFile(tempFile);

HANDLE hSourceFile = INVALID_HANDLE_VALUE;
HANDLE hDestinationFile = INVALID_HANDLE_VALUE;
HCRYPTPROV hCryptProv = NULL;
HCRYPTKEY hKey = NULL;
HCRYPTKEY hXchgKey = NULL;
HCRYPTHASH hHash = NULL;
PBYTE pbKeyBlob = NULL;
DWORD dwKeyBlobLen;
PBYTE pbBuffer = NULL;
DWORD dwBlockLen;
DWORD dwBufferLen;
DWORD dwCount;
bool fEOF = FALSE;

char pszPassword[] = "key";

char s[] = "C:\\pg\\openText.txt";
char d[] = "C:\\pg\\cryptoText.txt";

hSourceFile = CreateFile(s, FILE_READ_DATA, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

if (INVALID_HANDLE_VALUE == hSourceFile)
{
    fprintf(log, "%u %s\n", GetLastError(), "CreateFile s");
    goto Exit_MyEncryptFile;
}

hDestinationFile = CreateFile(d, FILE_WRITE_DATA, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);

if (INVALID_HANDLE_VALUE == hDestinationFile)
{
    fprintf(log, "%u %s\n", GetLastError(), "CreateFile d");
    goto Exit_MyEncryptFile;
}

if (!CryptAcquireContext(&hCryptProv, NULL, MS_ENHANCED_PROV, PROV_RSA_FULL, 0))
{
    fprintf(log, "%u %s\n", GetLastError(), "CryptAcquireContext");
    goto Exit_MyEncryptFile;
}

if (!CryptCreateHash(hCryptProv, CALG_MD5, 0, 0, &hHash))
{
    fprintf(log, "%u %s\n", GetLastError(), "CryptCreateHash");
    goto Exit_MyEncryptFile;
}

if (!CryptHashData(hHash, (BYTE*)pszPassword, lstrlen(pszPassword), 0))
{
    fprintf(log, "%u %s\n", GetLastError(), "CryptHashData");
    goto Exit_MyEncryptFile;
}

if (!CryptDeriveKey(hCryptProv, ENCRYPT_ALGORITHM, hHash, KEYLENGTH, &hKey))
{
    fprintf(log, "%u %s\n", GetLastError(), "CryptDeriveKey");
    goto Exit_MyEncryptFile;
}

dwBlockLen = 1000 - 1000 % ENCRYPT_BLOCK_SIZE;

if (ENCRYPT_BLOCK_SIZE > 1)
    dwBufferLen = dwBlockLen + ENCRYPT_BLOCK_SIZE;
else
    dwBufferLen = dwBlockLen;

pbBuffer = (BYTE*)malloc(dwBufferLen);

do
{
    if (!ReadFile(hSourceFile, pbBuffer, dwBlockLen, &dwCount, NULL))
    {
        fprintf(log, "%u %s\n", GetLastError(), "ReadFile");
        goto Exit_MyEncryptFile;
    }

    if (dwCount < dwBlockLen)
        fEOF = TRUE;

    if (!CryptEncrypt(hKey, NULL, fEOF, 0, pbBuffer, &dwCount, dwBufferLen))
    {
        fprintf(log, "%u %s\n", GetLastError(), "CryptEncrypt");
        goto Exit_MyEncryptFile;
    }

    if (!WriteFile(hDestinationFile, pbBuffer, dwCount, &dwCount, NULL))
    {
        fprintf(log, "%u %s\n", GetLastError(), "WriteFile");
        goto Exit_MyEncryptFile;
    }

} while (!fEOF);
2
  • 2
    DWORD dw = sizeof(data); This cannot possibly be correct; sizeof(data) is the size of the pointer variable, not the size of the bytea datum you retrieved from the database. I don't know what the correct way to get the length of the datum is (which is why this is not an answer) but I'm pretty sure this is the cause of your problem. Commented May 12, 2020 at 13:21
  • I triedvarious sizes, It did not help. It read thesame thing Commented May 12, 2020 at 13:50

1 Answer 1

2

You don't show us the function that creates that bytea, so I have no idea if you did it right.

But you most certainly messed up the second function:

A bytea is not a string. If you read in src/include/fmgr.h,

/*
 * Support for fetching detoasted copies of toastable datatypes (all of
 * which are varlena types).  pg_detoast_datum() gives you either the input
 * datum (if not toasted) or a detoasted copy allocated with palloc().
 * pg_detoast_datum_copy() always gives you a palloc'd copy --- use it
 * if you need a modifiable copy of the input.  Caller is expected to have
 * checked for null inputs first, if necessary.
 *
 * pg_detoast_datum_packed() will return packed (1-byte header) datums
 * unmodified.  It will still expand an externally toasted or compressed datum.
 * The resulting datum can be accessed using VARSIZE_ANY() and VARDATA_ANY()
 * (beware of multiple evaluations in those macros!)
 *
 * In consumers oblivious to data alignment, call PG_DETOAST_DATUM_PACKED(),
 * VARDATA_ANY(), VARSIZE_ANY() and VARSIZE_ANY_EXHDR().  Elsewhere, call
 * PG_DETOAST_DATUM(), VARDATA() and VARSIZE().  Directly fetching an int16,
 * int32 or wider field in the struct representing the datum layout requires
 * aligned data.  memcpy() is alignment-oblivious, as are most operations on
 * datatypes, such as text, whose layout struct contains only char fields.
 *
 * Note: it'd be nice if these could be macros, but I see no way to do that
 * without evaluating the arguments multiple times, which is NOT acceptable.
 */

Now, since bytea is a varlena type, the code should look somewhat like this:

bytea* data = PG_GETARG_BYTEA_PP(0);
uint32 data_length = VARSIZE_ANY(data);
char *raw_data = VARDATA_ANY(data);

WriteFile(h, raw_data, data_length, &dw, NULL);
Sign up to request clarification or add additional context in comments.

6 Comments

in that case result is zvf  Њ<
So? Is that wrong? As I said, I cannot vouch for the first function, which you didn't show.
first function just get cstring and use microsoft cryptoapi to encrypt cstring. As a result we have BYTE array, i put it in table like bytea. In this reason I did not think that first function is important.
Well, you may have messed up that first part, just like you messed up the second function.
Should data_length really be int and not size_t?
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.