Hi Everyone,
I am having my first crack at using the Crypto API and am having problems
exporting and importing DH keys. What I'm doing is generate a DH key set,
exporting the public and private keys to a pair of blobs, writing them to a
disk file then reading them back in and trying to import them. The import
of the private key is just fine but when I try to import the public key I
get a NTE_BAD_KEY error thrown. Can anyone help me out with this.
Essentially all I'm doing is calling the OnGenerateEncrypKey() and then the
OnImportKey(). When I call the OnImportKey function I select from the
dialog the public key file that was created in the OnGenerateEncrypKey()
call. The eventual goal is to get the public key stored on disk so that I
can distribute it with my software and then use it to decode information
that I have created using the private key. I would like to also have the
private key backed up onto a disk for safety sake. Any help on what I might
be missing here would be a great help.
My code is as follows:
////////////////////////////////////////////////////////////////////////////
/
// CECCRLicenseToolDlg message handlers
BOOL CECCRLicenseToolDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// Add "About..." menu item to system menu.
// IDM_ABOUTBOX must be in the system command range.
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);
CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != NULL)
{
CString strAboutMenu;
strAboutMenu.LoadString(IDS_ABOUTBOX);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
}
// Set the icon for this dialog. The framework does this automatically
// when the application's main window is not a dialog
SetIcon(m_hIcon, TRUE); // Set big icon
SetIcon(m_hIcon, FALSE); // Set small icon
// TODO: Add extra initialization here
m_hCryptProv = NULL;
m_hExportPubKey = NULL;
m_hExportPrivKey= NULL;
m_hSessionKey = NULL;
// Add the types of License to the combobox.
CComboBox *pCombo = (CComboBox*)GetDlgItem(IDC_COMBO1);
pCombo->AddString("SEAT");
pCombo->AddString("TIME");
// Set the key display to have EOL automatically inserted.
CEdit *display = (CEdit *) GetDlgItem(IDC_EDIT6);
display->FmtLines(true);
Init();
return TRUE; // return TRUE unless you set the focus to a control
}
//**************************************************************************
***********************************************
//**************************************************************************
***********************************************
BOOL CECCRLicenseToolDlg::CanExit()
{
// If the proxy object is still around, then the automation
// controller is still holding on to this application. Leave
// the dialog around, but hide its UI.
if (m_pAutoProxy != NULL)
{
ShowWindow(SW_HIDE);
return FALSE;
}
if(m_hCryptProv != NULL)
CryptReleaseContext(m_hCryptProv, 0);
return TRUE;
}
//**************************************************************************
***********************************************
// Create a public and private key pair then store them to a file.
void CECCRLicenseToolDlg::OnGenerateEncrypKey()
{
CString csStr;
HCRYPTKEY hKey;
// Now get the key pair for asymetic encryption (AT_KEYEXCHANGE)
if(!(CryptGenKey(m_hCryptProv,AT_KEYEXCHANGE,CRYPT_EXPORTABLE,&hKey))){
CryptError("Error trying to create the exchange pair.");
return;
}
ExportAsymKeys(hKey);
}
//**************************************************************************
***********************************************
// Gets the cryptography interface and loads the key pair for this user.
// This Asymetric key set will be used to create the Autherization Code.
bool CECCRLicenseToolDlg::Init()
{
if(m_hCryptProv != NULL)
CryptReleaseContext(m_hCryptProv, 0);
// Get the Diffie-Hellman service provider.
if(!(CryptAcquireContext(&m_hCryptProv, "ECCR", MS_DEF_DSS_DH_PROV,
PROV_DSS_DH, 0)))
{
CryptError("Attempting to create a new key set. ");
if(!CryptAcquireContext(&m_hCryptProv, "ECCR", MS_DEF_DSS_DH_PROV,
PROV_DSS_DH, CRYPT_NEWKEYSET))
{
CryptError("Error getting new keys in the context.");
return false;
} }
return true;
}
//**************************************************************************
***********************************************
// Exports the current keys held by the current crypto provider.
bool CECCRLicenseToolDlg::ExportAsymKeys(HCRYPTKEY hKey)
{
unsigned long ulPathIndex, ulIndex;
BYTE *psBuffer;
DWORD dwKeySize;
CString csPath,OutputString;
ASSERT(m_hCryptProv != NULL);
// Get the destination directory.
CString strPath("");
CFileDialog cFile(TRUE, NULL, NULL,
OFN_OVERWRITEPROMPT|OFN_PATHMUSTEXIST|OFN_LONGNAMES); //
OFN_FILEMUSTEXIST - use to get an existing Key.
if(cFile.DoModal() == IDOK){
strPath = cFile.GetPathName();
}
// Isolate the path from the file name!
ulIndex = 0;
while((ulIndex = strPath.Find('\\',ulIndex)+1) != -1)
{
if(strPath.Find('\\',ulIndex) == -1){
ulPathIndex = ulIndex;
break;
} }
csPath = strPath.Left(ulPathIndex);
if(!CryptExportKey(hKey,NULL,PUBLICKEYBLOB,0,NULL, &dwKeySize)){
CryptError("Error getting the length of the Public key.");
return false;
}
psBuffer = new BYTE[dwKeySize];
if(!CryptExportKey(hKey,NULL,PUBLICKEYBLOB,0,psBuffer, &dwKeySize)){
CryptError("Error getting the Public key.");
return false;
}
// now store the key to a file.
CFile publicKey(csPath+"publickey.key",
CFile::modeWrite|CFile::modeCreate);
publicKey.Write(static_cast<void*> (psBuffer),dwKeySize);
publicKey.Close();
// Display the key on screen.
OutputString += "Public Key:\r\n";
char *pszPublicKey = new char[2*(dwKeySize+(dwKeySize%30))+1];
*pszPublicKey = '\0';
int i=0;
for(int n=0; n<dwKeySize; n++){
sprintf(&pszPublicKey[i], "%02x", psBuffer[n]);
i += 2;
if((n+1)%30 == 0){
pszPublicKey[i] = '\r';
pszPublicKey[i+1]= '\n';
i += 2;
} }
OutputString += pszPublicKey;
OutputString += "\r\n\r\nPrivate Key:\r\n";
delete pszPublicKey;
delete [] psBuffer;
if(!CryptExportKey(hKey,NULL,PRIVATEKEYBLOB,0,NULL, &dwKeySize)){
CryptError("Error getting the length of the Private key.");
return false;
}
psBuffer = new BYTE[dwKeySize];
if(!CryptExportKey(hKey,NULL,PRIVATEKEYBLOB,0,psBuffer, &dwKeySize)){
CryptError("Error exporting the Private key.");
return false;
}
// now store the key to a file.
CFile privateKey(csPath+"privatekey.key",
CFile::modeWrite|CFile::modeCreate);
privateKey.Write(static_cast<void*> (psBuffer),dwKeySize);
privateKey.Close();
//************************************
// Display the key on screen.
pszPublicKey = new char[2*(dwKeySize+(dwKeySize%30))+1];
*pszPublicKey = '\0';
i=0;
for(n=0; n<dwKeySize; n++)
{
sprintf(&pszPublicKey[i], "%02x", psBuffer[n]);
i += 2;
if((n+1)%30 == 0){
pszPublicKey[i] = '\r';
pszPublicKey[i+1]= '\n';
i += 2;
}
}
OutputString += pszPublicKey;
delete pszPublicKey;
delete [] psBuffer;
SetDlgItemText(IDC_EDIT6,OutputString);
return true;
}
//**************************************************************************
***********************************************
// Loads a key from the designated file into memory and inputs it to the
current
// crypto provider. If the interface is not initialized it will be using
this key.
bool CECCRLicenseToolDlg::ImportKeys()
{
// Get the destination directory.
BYTE *psBuffer;
DWORD ulKeySize = 0;
CString strPath("");
CFileDialog cFile(TRUE, NULL, NULL, OFN_PATHMUSTEXIST|OFN_FILEMUSTEXIST);
// OFN_FILEMUSTEXIST - use to get an existing Key.
// Import the public key from file.
MessageBox("Select public key source file.");
if(cFile.DoModal() == IDOK){
strPath = cFile.GetPathName();
}
// now store the key to a file.
CFile publicKey(strPath, CFile::modeRead);
ulKeySize = publicKey.GetLength();
psBuffer = new BYTE[ulKeySize];
publicKey.ReadHuge(static_cast<void*> (psBuffer),ulKeySize);
// Because this is not a public private key pair we don't need to worry
about the CRYPT_EXPORTABLE flag!
if(!CryptImportKey(m_hCryptProv, psBuffer, ulKeySize, NULL, 0,
&m_hExportPubKey)){
CryptError("Error importing the Public key.");
delete [] psBuffer;
return false;
}
delete [] psBuffer;
// Import the private key from file.
MessageBox("Select private key source file.");
if(cFile.DoModal() == IDOK){
strPath = cFile.GetPathName();
}
// now store the key to a file.
CFile privateKey(strPath, CFile::modeRead);
ulKeySize = privateKey.GetLength();
psBuffer = new BYTE[ulKeySize];
publicKey.ReadHuge(static_cast<void*> (psBuffer),ulKeySize);
if(!CryptImportKey(m_hCryptProv, psBuffer, ulKeySize, NULL,
CRYPT_EXPORTABLE, &m_hExportPubKey)){
CryptError("Error importing the private key.");
delete [] psBuffer;
return false;
}
delete [] psBuffer;
publicKey.Close();
privateKey.Close();
return true;
}
//**************************************************************************
***********************************************
void CECCRLicenseToolDlg::OnImport()
{
ImportKeys();
}
//**************************************************************************
***********************************************
void CECCRLicenseToolDlg::CryptError(CString csMsg)
{
char sTemp[256];
DWORD e;
csMsg += "\n\nERROR: ";
e = GetLastError();
switch(e) {
case NTE_BAD_KEY:
csMsg += "NTE_BAD_KEY - ";
break;
case ERROR_INVALID_HANDLE:
csMsg += "ERROR_INVALID_HANDLE - ";
break;
case ERROR_INVALID_PARAMETER:
csMsg += "ERROR_INVALID_PARAMETER - ";
break;
case ERROR_MORE_DATA:
csMsg += "ERROR_MORE_DATA - ";
break;
case NTE_BAD_FLAGS:
csMsg += "NTE_BAD_FLAGS - ";
break;
case NTE_BAD_KEY_STATE:
csMsg += "NTE_BAD_KEY_STATE - ";
break;
case NTE_BAD_PUBLIC_KEY:
csMsg += "NTE_BAD_PUBLIC_KEY - ";
break;
case NTE_BAD_TYPE:
csMsg += "NTE_BAD_TYPE - ";
break;
case NTE_BAD_UID:
csMsg += "NTE_BAD_UID - ";
break;
case NTE_NO_KEY:
csMsg += "NTE_NO_KEY - ";
break;
default:
csMsg += "Unknown error - ";
}
sprintf(sTemp,"0x%x\n",e);
csMsg += sTemp;
MessageBox(csMsg,"Crypto Error",MB_ICONERROR);
}
//**************************************************************************
***********************************************
void CECCRLicenseToolDlg::OnDeleteAllKeys()
{
CString str;
HCRYPTKEY hKey;
DWORD dwRC;
// Get the Diffie-Hellman service provider.
if(!(CryptAcquireContext(&m_hCryptProv, "ECCR", MS_DEF_DSS_DH_PROV,
PROV_DSS_DH, CRYPT_DELETEKEYSET)))
CryptError("Error deleting the key container."); // Display error and
exit.
else{
// Reinitialize the context with a new key set.
if(!CryptAcquireContext(&m_hCryptProv, "ECCR", MS_DEF_DSS_DH_PROV,
PROV_DSS_DH, CRYPT_NEWKEYSET))
CryptError("Error recreating the container after deletion.");
MessageBox("The keys have been deleted.");
}
}