0

I am working with the crypto libraries and I am trying to create a simple password algorithm with the libraries. I used MSDN's Deriving a Session Key from a Password to generate keys by passing in a "username", but I'm not sure how to get the key back to test against my algorithm. The algorithm takes the username passed above and the key generated. I attempted using CryptDeriveKey and CryptGetKeyParam but it does not return the key.

How else could this be achieved ?

#include <stdio.h>
#include <string.h>
#include <conio.h>
#include <windows.h>
#include <Wincrypt.h>

#include <string.h>
#include <stdio.h>
#pragma comment( lib, "Advapi32.lib" )
#pragma comment( lib, "Rpcrt4.lib" )
#pragma comment( lib, "Ole32.lib" )
#pragma comment( lib, "Winhttp.lib" )
#pragma comment( lib, "Crypt32.lib" )

#include <tchar.h>
#include <stdio.h>

#pragma comment(lib, "crypt32.lib")


// Data to be encrypted.
// 
#define PLAIN_TEXT   TEXT("Michael Scott")

// 
// Private key with exponent of one.
// 
static BYTE PrivateKeyWithExponentOfOne[] =
{
   0x07, 0x02, 0x00, 0x00, 0x00, 0xA4, 0x00, 0x00,
   0x52, 0x53, 0x41, 0x32, 0x00, 0x02, 0x00, 0x00,
   0x01, 0x00, 0x00, 0x00, 0xAB, 0xEF, 0xFA, 0xC6,
   0x7D, 0xE8, 0xDE, 0xFB, 0x68, 0x38, 0x09, 0x92,
   0xD9, 0x42, 0x7E, 0x6B, 0x89, 0x9E, 0x21, 0xD7,
   0x52, 0x1C, 0x99, 0x3C, 0x17, 0x48, 0x4E, 0x3A,
   0x44, 0x02, 0xF2, 0xFA, 0x74, 0x57, 0xDA, 0xE4,
   0xD3, 0xC0, 0x35, 0x67, 0xFA, 0x6E, 0xDF, 0x78,
   0x4C, 0x75, 0x35, 0x1C, 0xA0, 0x74, 0x49, 0xE3,
   0x20, 0x13, 0x71, 0x35, 0x65, 0xDF, 0x12, 0x20,
   0xF5, 0xF5, 0xF5, 0xC1, 0xED, 0x5C, 0x91, 0x36,
   0x75, 0xB0, 0xA9, 0x9C, 0x04, 0xDB, 0x0C, 0x8C,
   0xBF, 0x99, 0x75, 0x13, 0x7E, 0x87, 0x80, 0x4B,
   0x71, 0x94, 0xB8, 0x00, 0xA0, 0x7D, 0xB7, 0x53,
   0xDD, 0x20, 0x63, 0xEE, 0xF7, 0x83, 0x41, 0xFE,
   0x16, 0xA7, 0x6E, 0xDF, 0x21, 0x7D, 0x76, 0xC0,
   0x85, 0xD5, 0x65, 0x7F, 0x00, 0x23, 0x57, 0x45,
   0x52, 0x02, 0x9D, 0xEA, 0x69, 0xAC, 0x1F, 0xFD,
   0x3F, 0x8C, 0x4A, 0xD0,

   0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

   0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

   0x64, 0xD5, 0xAA, 0xB1,
   0xA6, 0x03, 0x18, 0x92, 0x03, 0xAA, 0x31, 0x2E,
   0x48, 0x4B, 0x65, 0x20, 0x99, 0xCD, 0xC6, 0x0C,
   0x15, 0x0C, 0xBF, 0x3E, 0xFF, 0x78, 0x95, 0x67,
   0xB1, 0x74, 0x5B, 0x60,

   0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};

extern "C" int __cdecl _tmain(int argc, _TCHAR* argv[])
{
DWORD       dwResult = 0;
HCRYPTPROV  hProv = 0;
HCRYPTKEY   hKey = 0;
HCRYPTKEY   hSessionKey = 0;
BYTE* pbBlob = NULL;
DWORD       cbBlob;
BYTE        byData[] = PLAIN_TEXT;
DWORD       cbData = sizeof(byData);
DWORD       dwIndex;

__try
{
    // 
    // Acquire context for default user.
    // 
    if (!CryptAcquireContext(&hProv, NULL, MS_DEF_PROV, PROV_RSA_FULL, 0))
    {
        dwResult = GetLastError();
        if (dwResult == NTE_BAD_KEYSET)
        {
            if (!CryptAcquireContext(&hProv, NULL, MS_DEF_PROV, PROV_RSA_FULL, CRYPT_NEWKEYSET))
            {
                dwResult = GetLastError();
                _tprintf(TEXT("Error [0x%x]: CryptAcquireContext() failed.\n"), dwResult);
                __leave;
            }
        }
        else
        {
            dwResult = GetLastError();
            __leave;
        }
    }

    // 
    // Import the exponent-of-one private key.
    // 
    if (!CryptImportKey(hProv,
        PrivateKeyWithExponentOfOne,
        sizeof(PrivateKeyWithExponentOfOne),
        0, 0, &hKey))
    {
        dwResult = GetLastError();
        _tprintf(TEXT("Error [0x%x]: CryptImportKey() failed.\n"), dwResult);
        __leave;
    }
    _tprintf(TEXT("%p\n"), &hKey);

    // 
    // Generate exportable session key.
    // 
    if (!CryptGenKey(hProv, CALG_RC4, CRYPT_EXPORTABLE, &hSessionKey))
    {
        dwResult = GetLastError();
        _tprintf(TEXT("Error [0x%x]: CryptGenKey() failed.\n"), dwResult);
        __leave;
    }
    //printf("%04x\n", &hSessionKey);
    // 
    // Display plain text.
    // 
    _tprintf(TEXT("Original text = [%s]\n"), byData);

    // 
    // Encrypt the data.
    // 
    if (!CryptEncrypt(hSessionKey, 0, TRUE, 0, byData, &cbData, cbData))
    {
        dwResult = GetLastError();
        _tprintf(TEXT("Error [0x%x]: CryptEncrypt() failed.\n"), dwResult);
        __leave;
    }

    // 
    // Display encrypted text.
    // 
    _tprintf(TEXT("Encrypted text = ["));
    for (dwIndex = 0; dwIndex < cbData; dwIndex++)
    {
        _tprintf(TEXT("%hhx"), byData[dwIndex]);
    }
    _tprintf(TEXT("]\n"));

    // 
    // Determine key blob size.
    // 
    if (!CryptExportKey(hSessionKey, hKey, SIMPLEBLOB, 0, NULL, &cbBlob))
    {
        dwResult = GetLastError();
        _tprintf(TEXT("Error [0x%x]: CryptExportKey() failed.\n"), dwResult);
        __leave;
    }

    // 
    // Allocate memory for key blob.
    // 
    if ((pbBlob = (BYTE*)LocalAlloc(LMEM_ZEROINIT, cbBlob)) == NULL)
    {
        dwResult = ERROR_NOT_ENOUGH_MEMORY;
        _tprintf(TEXT("Error [0x%x]: LocalAlloc() failed.\n"), dwResult);
        __leave;
    }

    // 
    // Export the session key. Resultant blob is the raw session key.
    // 
    if (!CryptExportKey(hSessionKey, hKey, SIMPLEBLOB, 0, pbBlob, &cbBlob))
    {
        dwResult = GetLastError();
        _tprintf(TEXT("Error [0x%x]: CryptExportKey() failed.\n"), dwResult);
        __leave;
    }

    // 
    // Destroy the session key.
    // 
    CryptDestroyKey(hSessionKey);
    hSessionKey = 0;

    // 
    // Import the session key back to decrypt the data.
    // 
    if (!CryptImportKey(hProv, pbBlob, cbBlob, 0, 0, &hSessionKey))
    {
        dwResult = GetLastError();
        _tprintf(TEXT("Error [0x%x]: CryptImportKey() failed.\n"), dwResult);
        __leave;
    }

    // 
    // Decrypt the data.
    // 
    if (!CryptDecrypt(hSessionKey, 0, TRUE, 0, byData, &cbData))
    {
        dwResult = GetLastError();
        _tprintf(TEXT("Error [0x%x]: CryptDecrypt() failed.\n"), dwResult);
        __leave;
    }

    // 
    // Make sure we got all the data back.
    // 
    if (cbData != sizeof(byData) || _tcscmp((const char*)byData, PLAIN_TEXT) != 0)
    {
        _tprintf(TEXT("Error: Data was not decrypted correctly.\n"));
        __leave;
    }

    // 
    // Display decrypted text.
    // 
    _tprintf(TEXT("Decrypted text = [%s]\n"), byData);
}

__finally
{
    // 
    // Release all allocated resources.
    // 
    if (pbBlob)
        LocalFree(pbBlob);

    if (hSessionKey)
        CryptDestroyKey(hSessionKey);

    if (hKey)
        CryptDestroyKey(hKey);

    if (hProv)
        CryptReleaseContext(hProv, 0);
}

return (int)dwResult;
}
droidnoob
  • 333
  • 5
  • 17
  • This is going back a ways and my memory is foggy... Those session keys are stored in a container. They are not intended to be returned to the user. To export one you need to supply an RSA key with an exponent of 1, which is effectively "no encryption". WinCrypt will encrypt the session key with the RSA key and then return it to you. – jww May 01 '19 at 20:42
  • could you please explain this further? I've been using your statement to try and find answers and I haven't found a thing – droidnoob May 02 '19 at 04:46
  • See this old Microsoft KB article: Q228786, [Export/Import Plain Text Session Key Using CryptoAPI](https://web.archive.org/web/20000603131602/http://support.microsoft.com/support/kb/articles/Q228/7/86.ASP). Here's another old article about it: [Setting the RC4 key in Windows CryptoAPI](https://www.phdcc.com/cryptorc4.htm). Once you know to search for Q228786, you can find lots of hits. – jww May 02 '19 at 05:29
  • I think this is the closest duplicate, but I think it misses some important points, like a session key cannot be easily exported: [How to export AES key derived using CryptoAPI](https://stackoverflow.com/q/29586097/608639). – jww May 02 '19 at 11:18
  • Could you take a look at what I have ? This STILL does not work. I've been up all night trying to figure it out and I got nowhere – droidnoob May 02 '19 at 13:36
  • The code you provided does not do what the knowledge base article tells you to do. You should do what the kb article tells you to do. – jww May 02 '19 at 15:55
  • I don't think you understand what I am trying to achieve. I have updated the code with the article you sent but it does not answer my question. It does encrypt and decrypt correctly. But the encrypted data changes. I need to be able to pass a name and password already generated and check that it matches and although it encrypts and decrypts, it does not work – droidnoob May 02 '19 at 17:12
  • I believe you are generating a random key with `CryptGenKey(hProv, CALG_RC4, CRYPT_EXPORTABLE, &hSessionKey)`. I don't see calls to `CryptDeriveKey` to derive the session key you formerly discussed. At this point I should probably step out of this conversation. – jww May 02 '19 at 17:23
  • RC4 and a private key with an exponent of ... one? What's the point of the code? – Maarten Bodewes May 03 '19 at 22:08

0 Answers0