-
crypto questions
I'm working on a program to export a public/private key pair that has been encrypted using a hashed password. i've been checking the error codes, and they all seem to check out okay, but i'm thinking the file output is incorrect (all i got was a single square in notepad, and a dot and a similey face in the cmd editor). maybe it has something to do with my pointers? i'm kinda stuck on this right now, so any help is appreciated. (unless it's working correctly as is :rolleyes: )
warning: long function ahead!
Code:
#include <iostream>
#include <windows.h>
#include <wincrypt.h>
#include <fstream>
#include <conio.h>
#include <string>
#include <cassert>
using namespace std;
void crypto();
int main()
{
crypto();
return 0;
}
void crypto()
{
HCRYPTPROV CSPhandle;
HCRYPTPROV CSPhandlePass;
HCRYPTKEY keyHandle;
HCRYPTKEY keyExpHandle;
HCRYPTKEY keyPassHandle;
HCRYPTHASH hashPassHandle;
// CHAR szContainerName;
LPCSTR ContainerName = "keyContainer";
CHAR ssPassword[512] = "password";
DWORD dwLength=strlen(ssPassword);
DWORD* blobSize;
BYTE* expData;
ofstream outfile;
string filename = "keys.dat";
int returnCode = 0;
DWORD errorCode = 0;
//creating a container for the public/private key pair:
if (returnCode = CryptAcquireContext(
&CSPhandle,
ContainerName,
NULL,
PROV_RSA_FULL,
0))
{
errorCode = GetLastError();
cout<<"An existing key container has been opened. " <<returnCode <<" " <<errorCode <<endl;
}
else
{
returnCode = CryptAcquireContext(
&CSPhandle,
ContainerName,
NULL,
PROV_RSA_FULL,
CRYPT_NEWKEYSET);
errorCode = GetLastError();
cout<<"A new key container has been created. " <<returnCode <<" " <<errorCode <<endl;
}
//generating the public/private key pair:
returnCode = CryptGenKey(
CSPhandle,
AT_SIGNATURE,
(1024U<<16) | CRYPT_EXPORTABLE,
&keyHandle);
errorCode = GetLastError();
cout<<"Created a signature key pair. " <<returnCode <<" " <<errorCode <<endl;
//creating a container for the password key:
if (returnCode = CryptAcquireContext(
&CSPhandlePass,
NULL,
NULL,
PROV_RSA_FULL,
CRYPT_NEWKEYSET))
{
errorCode = GetLastError();
cout<<"A new key container has been created for the password hash. " <<returnCode <<" " <<errorCode <<endl;
}
else
{
returnCode = CryptAcquireContext(
&CSPhandlePass,
NULL,
NULL,
PROV_RSA_FULL,
0);
errorCode = GetLastError();
cout<<"An existing container has been opened for the password hash. " <<returnCode <<" " <<errorCode <<endl;
}
//creating hash object for hashing the password:
returnCode = CryptCreateHash(
CSPhandlePass,
CALG_MD5,
0,
0,
&hashPassHandle);
errorCode = GetLastError();
cout<<"An empty hash object has been created. " <<returnCode <<" " <<errorCode <<endl;
//hashing the password string:
returnCode = CryptHashData(
hashPassHandle,
(BYTE *)ssPassword,
dwLength,
0);
errorCode = GetLastError();
cout<<"Password hashed. " <<returnCode <<" " <<errorCode <<endl;
//creating a key based on the password:
returnCode = CryptDeriveKey(
CSPhandlePass,
CALG_RC2,
hashPassHandle,
0,
&keyPassHandle);
errorCode = GetLastError();
cout<<"Password key created. " <<returnCode <<" " <<errorCode <<endl;
//setting the export key to the key derived from password:
keyExpHandle = keyPassHandle;
//exporting the encrypted public/private key pair:
//getting the size of the data:
blobSize = new DWORD;
*blobSize = 0;
returnCode = CryptExportKey(
keyHandle,
0,
PRIVATEKEYBLOB,
0,
NULL,
blobSize);
errorCode = GetLastError();
cout<<"Return code / error code for sizing CEK call: " <<returnCode <<" " <<errorCode <<endl;
/* cout<<"Error codes:\n";
cout<<ERROR_INVALID_HANDLE <<endl;
cout<<ERROR_INVALID_PARAMETER <<endl;
cout<<ERROR_MORE_DATA <<endl;
cout<<(unsigned int)NTE_BAD_FLAGS <<endl;
cout<<(unsigned int)NTE_BAD_KEY <<endl;
cout<<(unsigned int)NTE_BAD_KEY_STATE <<endl;
cout<<(unsigned int)NTE_BAD_PUBLIC_KEY <<endl;
cout<<(unsigned int)NTE_BAD_TYPE <<endl;
cout<<(unsigned int)NTE_BAD_UID <<endl;
cout<<(unsigned int)NTE_NO_KEY <<endl;
*/
expData = new BYTE[*blobSize];
//exporting the data:
returnCode = CryptExportKey(
keyHandle,
0,
PRIVATEKEYBLOB,
NULL,
expData,
blobSize);
errorCode = GetLastError();
cout<<"Keys exported to expData. " <<returnCode <<" " <<errorCode <<endl;
//writing encrypted keys to file:
outfile.open(filename.c_str());
assert(outfile);
outfile<<expData;
cout<<expData <<endl;
outfile.close();
//cleaning up handles, etc.
delete blobSize;
delete expData;
CryptDestroyKey(keyHandle);
CryptDestroyKey(keyExpHandle);
CryptDestroyKey(keyPassHandle);
CryptDestroyHash(hashPassHandle);
CryptReleaseContext(CSPhandle, 0);
CryptReleaseContext(CSPhandlePass, 0);
}
-
well, i fixed the file output problem, just writing the file with binary instead of using the useless insertion operator.
one more question: when i try to use the key that i generated from the hashed password, i get an invalid key error in the CryptExportKey calls.
Code:
//setting the export key to the key derived from password:
keyExpHandle = keyPassHandle;
//exporting the encrypted public/private key pair:
//getting the size of the data:
blobSize = new DWORD;
*blobSize = 0;
returnCode = CryptExportKey(
keyHandle,
0,
PRIVATEKEYBLOB,
0,
NULL,
blobSize);
errorCode = GetLastError();
cout<<"Return code / error code for sizing CEK call: " <<returnCode <<" " <<errorCode <<endl;
expData = new BYTE[*blobSize];
//exporting the data:
returnCode = CryptExportKey(
keyHandle,
0,
PRIVATEKEYBLOB,
NULL,
expData,
blobSize);
the code works fine when i substitute 0 for the hExpKey (the 2nd parameter to CryptExportKey), but the output is not going to be encrypted. i tried both keyExpHandle and keyPassHandle in case it was something wrong with the assignment of the key, but met with the same result.
any ideas?