【实例介绍】:
在《轻松看懂的加解密系列(1)》中,我们用一个简单的 Windows Console 程序介绍了 Windows Crypto APIs 是如何进行 AES 对称加密和解密的。这次将通过另一个 Windows MFC 对话框程序,来讲解更复杂一些的 RSA 非对称加密接口的运用。当然本实例继续使用 Windows Crypto APIs。

看到【图-1】中的对话框,如果稍有 Windows 编程基础,应该大致就能猜到点击【Encrypt By Public Key】按钮或【Decrypt By Private Key】按钮会各触发一个事件响应函数。函数名分别为【OnBnClickedButtonEncrypt】和【OnBnClickedButtonDecrypt】。其中【OnBnClickedButtonEncrypt】函数会从第一个对话框中取出用户输入的明文,然后用生成的公钥加密后,将密文以及对应生成的私钥一并存储在目标注册表项下。【OnBnClickedButtonDecrypt】函数会从目标注册表项读取密文和私钥,经解密后再输出到第二个对话框中。由于密钥和机器是无关的,所以可以在 A 电脑上用测试程序完成加密动作,然后将目标注册表项导出到 B 电脑上用同样的测试程序完成解密动作。
public:
afx_msg void OnBnClickedButtonEncrypt();
afx_msg void OnBnClickedButtonDecrypt();
private:
void ShowError(const char* pszText);
BOOL ReturnPublicKeyStorePrivateKey(BYTE** ppPublicKey, DWORD* pdwPublicKeyLength);
BOOL RsaEncrypt(BYTE* pPublicKey, DWORD dwPublicKeyLength, BYTE* pData, DWORD& dwDataLength, DWORD dwBufferLength);
BOOL RsaDecrypt(BYTE* pPrivateKey, DWORD dwProvateKeyLength, BYTE* pData, DWORD& dwDataLength);
为了完成以上描述的任务,例程封装了3个 private 函数:
- 【ReturnPublicKeyStorePrivateKey】负责生成公钥和私钥,然后存储私钥,导出公钥;
- 【RsaEncrypt】负责用公钥加密明文,并返回给调用方存储密文;
- 【RsaDecrypt】负责用私钥解密密文,并输出;
【OnBnClickedButtonEncrypt】:
void CCryptoApiRsaMfcTestDlg::OnBnClickedButtonEncrypt()
{
// Generate public and store private key into target register path
BYTE* pData = NULL;
DWORD dwBufferLength = 2048;
pData = new BYTE[dwBufferLength];
if (NULL == pData)
{
AfxMessageBox(_T("Create pData failure!"), MB_ICONERROR);
return;
}
CEdit* pEdit = (CEdit*)GetDlgItem(IDC_EDIT_TOBE);
CString strText;
pEdit->GetWindowText(strText);
int bufferSize = WideCharToMultiByte(CP_UTF8, 0, strText, -1, NULL, 0, NULL, NULL);
if (bufferSize > 0)
{
char* pMultiByteText = new char[bufferSize];
WideCharToMultiByte(CP_UTF8, 0, strText, -1, pMultiByteText, bufferSize, NULL, NULL);
DWORD dwTextLength = strlen(pMultiByteText);
if (dwTextLength <= dwBufferLength)
{
memcpy(pData, pMultiByteText, dwTextLength);
pData[dwTextLength] = '\0';
}
else
{
AfxMessageBox(_T("dwTextLength > dwBufferLength!"), MB_ICONERROR);
return;
}
delete[] pMultiByteText;
}
else
{
AfxMessageBox(_T("No input, bufferSize <= 0!"), MB_ICONERROR);
return;
}
BYTE* pPublicKey = NULL;
DWORD dwPublicKeyLength = 0;
ReturnPublicKeyStorePrivateKey(&pPublicKey, &dwPublicKeyLength);
// Use public key to encrypt input
DWORD dwDataLength = 0;
dwDataLength = 1 + ::lstrlenA((char*)pData);
RsaEncrypt(pPublicKey, dwPublicKeyLength, pData, dwDataLength, dwBufferLength);
// Store encrypted input into target register path
CString strAppName = AfxGetAppName();
CString strRegistryPath;
strRegistryPath.Format(_T("SOFTWARE\\%s"), strAppName);
LPCTSTR lpRegistryPath = strRegistryPath.GetBuffer();
HKEY hKey;
LONG result = RegCreateKeyEx(HKEY_CURRENT_USER, lpRegistryPath, 0, NULL, 0, KEY_WRITE, NULL, &hKey, NULL);
if (result == ERROR_SUCCESS)
{
result = RegSetValueEx