为了这个为对称加密的程序忙活了一阵子了。
HCRYPTPROV hProv,
ALG_ID Algid,
DWORD dwFlags,
HCRYPTKEY* phKey
);
注意CryptGenKey的参数:
- hProv
- A handle to a cryptographic service provider (CSP) created by a call to CryptAcquireContext.
- Algid
- An ALG_ID value that identifies the algorithm for which the key is to be generated. Values for this parameter vary depending on the CSP used.
For a Diffie-Hellman CSP, use one of the following values.
Value Meaning CALG_DH_EPHEM Specifies an "Ephemeral" Diffie-Hellman key. CALG_DH_SF Specifies a "Store and Forward" Diffie-Hellman key. In addition to generating session keys for symmetric algorithms, this function can also generate public/private key pairs. Each CryptoAPI client generally possesses two public/private key pairs. To generate one of these key pairs, set the Algid parameter to one of the following values.
Value Meaning AT_KEYEXCHANGE Key exchange AT_SIGNATURE Digital signature CryptGetKeyParam (when the KP_ALGID parameter is specified) depend on the provider used. To determine which algorithm identifier is used by the different providers for the key specs AT_KEYEXCHANGE and AT_SIGNATURE, see ALG_ID.
- dwFlags
Specifies the type of key generated. The sizes of a session key,RSA signature key, and RSA key exchange keys can be set when the key is generated.
- phKey
- [out] Address to which the function copies the handle of the newly generated key. When you have finished using the key, delete the handle to the key by calling the CryptDestroyKey function.
上面这些都是msdn上的一些内容,产生非对称加密key对的话,只要把第二个参数输入AT_KEYEXCHANGE就可以了。
- 然后加密,导出key,都没有太大的悬念,但是有个问题困扰过我一段时间。就是关于CSP的非对称加密长度的问题。默认是117字节。但是我一直以为可以修改某个参数而实现对长文本的加密。但是最终也没有找到一个方法。最后我只好采用了分组加密的方法。关键方法如下:
加密:
/**********************************************************************
+Function name: CRYPTAPI_RSAEncrypt(unsigned char *pbSrcData, int nSrcLen, unsigned char *pbDestData, int &nDestLen)
+Input parameter: 'pbSrcData' Encrypting data
'nSrcLen' Length of encrypting data
'pbDestData' Encrypted data
'nDestLen' Length of encrypted data
+output parameter: 'pbDestData' Encrypted data
'nDestLen' Length of encrypted data
+Return:
+Remark: Encrypt data by private key
***********************************************************************/
int CKeyOperation::CRYPTAPI_RSAEncrypt(unsigned char *pbSrcData, int nSrcLen,
unsigned char *pbDestData, int &nDestLen,
BYTE *pbPubKey, DWORD &dwPubKeyLen,
BYTE *pbPriKey, DWORD &dwPriKeyLen)//nDestLen = (nSrcLen/117 +1)*128
{
int r;
CryptAcquireContext(&m_hProv, "ASYENCRYPT", MS_ENHANCED_PROV, PROV_RSA_FULL, CRYPT_DELETEKEYSET);
if(!CryptAcquireContext(&m_hProv, "ASYENCRYPT", MS_ENHANCED_PROV, PROV_RSA_FULL, CRYPT_NEWKEYSET))
return -1;
//Gennerate key pair
if(!CryptGenKey(m_hProv, AT_KEYEXCHANGE, CRYPT_EXPORTABLE, &m_hKey))
{
//Delete container
CryptAcquireContext(&m_hProv, "ASYENCRYPT", MS_ENHANCED_PROV,
PROV_RSA_FULL, CRYPT_DELETEKEYSET);
CryptReleaseContext(m_hProv, 0);
return -2;
}
//unsigned char *tempDestData = new unsigned char[nDestLen];
unsigned char *tempDivSrcData = new unsigned char[128+1];
int j=0;
int t=0;
//r = CryptEncrypt(m_hKey, 0, TRUE, 0, pbSrcData, (unsigned long *)&nSrcLen, 2048);
for(int i=0;i*117<nSrcLen;i++)
{
memset(tempDivSrcData,0x00,128+1);
for(j=0;j<117&&j<nSrcLen;j++)
{
tempDivSrcData[j]=pbSrcData[(i*117)+j];
}
r = CryptEncrypt(m_hKey, 0, TRUE, 0, tempDivSrcData, (unsigned long *)&j, 128);
if(!r)
{
if(m_hProv)
CryptReleaseContext(m_hProv, 0);
if(m_hKey)
CryptDestroyKey(m_hKey);
return -2;
}
t += j;
for(int m = 0;m<j;m++)
{
pbDestData[(i*j)+m] = tempDivSrcData[m];
//memcpy(pbDestData,tempDivSrcData,
}
}
nDestLen = t;
//memcpy(pbDestData, pbSrcData, nDestLen);
//Export privatekey
DWORD dwTempPriLen;
r = CryptExportKey(m_hKey, NULL, PRIVATEKEYBLOB, NULL, NULL, &dwTempPriLen);
if(!r)
{
//Failed to export the length of privatekey
if(m_hProv)
CryptReleaseContext(m_hProv, 0);
if(m_hKey)
CryptDestroyKey(m_hKey);
return -5;
}
BYTE *pbTempPriData = (BYTE *)malloc(dwTempPriLen+1);
r = CryptExportKey(m_hKey, NULL, PRIVATEKEYBLOB, NULL, pbTempPriData, &dwTempPriLen);
if(!r)
{
//Failed to export privatekey
if(m_hProv)
CryptReleaseContext(m_hProv, 0);
if(m_hKey)
CryptDestroyKey(m_hKey);
return -6;
}
//Export public key
DWORD dwTempPubLen;
r = CryptExportKey(m_hKey, NULL, PUBLICKEYBLOB, NULL, NULL, &dwTempPubLen);
if(!r)
{
//Failed to export the length of public key
if(m_hProv)
CryptReleaseContext(m_hProv, 0);
if(m_hKey)
CryptDestroyKey(m_hKey);
return -7;
}
BYTE *pbTempPubData = (BYTE *)malloc(dwTempPubLen+1);
r = CryptExportKey(m_hKey, NULL, PUBLICKEYBLOB, NULL, pbTempPubData, &dwTempPubLen);
if(!r)
{
//Failed to export public key
if(m_hProv)
CryptReleaseContext(m_hProv, 0);
if(m_hKey)
CryptDestroyKey(m_hKey);
return -8;
}
//Copy buffer
memcpy(pbPriKey, pbTempPriData, dwTempPriLen); //Copy data of private key
dwPubKeyLen = dwTempPubLen; //Length of private key
memcpy(pbPubKey, pbTempPubData, dwTempPubLen); //Copy data of public key
dwPriKeyLen = dwTempPriLen; //Length of public key
//Delete container
//CryptAcquireContext(&hProv, "RSA", MS_ENHANCED_PROV, PROV_RSA_FULL, CRYPT_DELETEKEYSET);
//Release memery
if(pbTempPriData)
free(pbTempPriData);
if(pbTempPubData)
free(pbTempPubData);
if(m_hKey)
CryptDestroyKey(m_hKey);
if(m_hProv)
CryptReleaseContext(m_hProv, 0);
return 0;
}
解密:
/**********************************************************************
+Function name: CRYPTAPI_RSADecrypt(unsigned char *pbSrcData, int nSrcLen, unsigned char *pbDestData, int &nDestLen,BYTE *pbPubKey, DWORD dwPubLen)
+Input parameter: unsigned char *pbSrcData,
int nSrcLen,
unsigned char *pbDestData,
int &nDestLen,
BYTE *pbPubKey,
DWORD dwPubLen
+output parameter: unsigned char *pbDestData,
int &nDestLen,
+Return:
+Remark: Decrypt the data with a imported key
***********************************************************************/
int CDecryptOperation::CRYPTAPI_RSADecrypt(unsigned char *pbSrcData, int nSrcLen,
unsigned char *pbDestData, int &nDestLen,
BYTE *pbPriKey, DWORD dwPriLen)
{
HCRYPTPROV m_hProv;
HCRYPTKEY m_hKey;
CryptAcquireContext(&m_hProv, "ASYENCRYPT", MS_ENHANCED_PROV, PROV_RSA_FULL, CRYPT_DELETEKEYSET);
if(!CryptAcquireContext(&m_hProv, "ASYENCRYPT", MS_ENHANCED_PROV, PROV_RSA_FULL, CRYPT_NEWKEYSET))
return -1;
int r;
// private key import
r = CryptImportKey(m_hProv, pbPriKey, dwPriLen, NULL, NULL, &m_hKey);
//Public key import
//r = CryptImportKey(m_hProv, pbPubKey, dwPubLen, NULL, NULL, &m_hKey);
if(!r)
{
return -4;
}
//int r = CryptDecrypt(m_hKey, 0, TRUE, 0, pbSrcData, (unsigned long *)&nSrcLen);
unsigned char *tempDivSrcData = new unsigned char[128+1];
int j=0;
int t=0;
for(int i=0;i*128<nSrcLen;i++)
{
memset(tempDivSrcData,0x00,128+1);
for(j=0;j<128&&j<nSrcLen;j++)
{
tempDivSrcData[j]=pbSrcData[(i*128)+j];
}
r = CryptDecrypt(m_hKey, 0, TRUE, 0, tempDivSrcData, (unsigned long *)&j);
if(!r)
{
if(m_hProv)
CryptReleaseContext(m_hProv, 0);
if(m_hKey)
CryptDestroyKey(m_hKey);
return -2;
}
t += j;
for(int m = 0;m<j;m++)
{
pbDestData[(i*j)+m] = tempDivSrcData[m];
}
}
if(!r)
{
return -3;
}
nDestLen = t;
return 0;
}
因为是初学c++,加密解密的内容又是第一次接触,程序完成的过程中参考了网上许多示例,但无法一一统计,向这些朋友的辛勤工作表示感谢。
当然,程序中许多不足的地方,比如内存泄漏(一听这个词我就心惊肉跳,就好像大冷天的,屋顶上扯开了道口子,因为时间紧,没时间看资料,我现在还不太清除该如何规范的写c++才能避免这些问题,因为我在c#使用的时候,很少过多的关心这些问题);看来以后要努力的学习了。
整理下自己的思路,也希望能给有类似需求的朋友一些启示。