用CNG加密文件的简单思路方法来源: 发布时间:星期五, 2009年2月20日 浏览:0次 评论:0
用CNG加密文件简单思路方法 介绍 文中用到了些Cryptography API Next Generation(CNG)开发环境为Windows Vista下Visual C 2005 SP1标准版加上Windows SDK及CNG SDK 可适用于以下情况: 在安全环境下保存文档但需要在不安全媒质(如互联网)中传送 加密文件如图像、MP3、各类文档 创建软件Software产品密钥 需要注意是CNG目前只支持Windows Vista且不能使用在Visual Basic及C#中要在Visual Studio中生成相应Windows可能还需要Windows Vista SDK及CNG SDK两者都可以从微软官方网站WebSite下载获得 背景 我们最初是想在个简单GUI中使用CNG来加密文件需要以下 3步: 1、 选择加密操作 2、 选择需要加密文件 3、 选择加密密钥 相关 此处创建了个MFC应用使用单文档界面在其中可选择待加解密文件、加密还是解密、密码;此外还有个列表框用于显示其他信息 另外要在Visual C 2005中使用CNG SDK还需要进行如下项目设置: 1、 在“C/C——General”项右方“Additional Include Directories”中添加以下目录:C:\Program Files\Microsoft CNG Development Kit\Include 2、 在“Link——General”项右方“Additional Library Directories”中添加以下目录:C:\Program Files\Microsoft CNG Development Kit\Lib\X86 3、 在“Linker——Input”项右方“Additional Dependencies”中添加“bcrypt.lib” 相关代码 在此使用CNG创建了类CMyCNGCryptFile它有 3个公有思路方法: EnumProviders:枚举出注册提供者 CryptFile:加密或解密个文件 GetLastError:返回发生在CryptFile或EnumProviders中最后个 相关步骤如下:1、打开算法提供者;2、创建或导入个密钥;3、获取或设置算法属性;4、执行操作;5、关闭算法提供者 以下是CNG API: 打开算法提供者: BCryptOpenAlgorithmProvider 导入密钥: BCryptGenerateSymmetricKey 创建密钥: BCryptCreateHash BCryptHashData BCryptFinishHash BCryptGenerateSymmetricKey 获取或设置算法属性: BCryptGetProperty BCryptSetProperty 执行加解密操作: BCryptEncrypt BCryptDecrypt 枚举提供者: BCryptEnumRegisteredProviders 关闭算法提供者: BCryptCloseAlgorithmProvider 销毁密钥: BCryptDestroyKey 销毁哈希: BCryptDestroyHash bool CryptFile(bool bEncrypt, CString sFileToOpen,CString sFileToCrypt,CString sKey) 这是从对话框中主要思路方法它接受要执行操作、输入文件、输出文件、密钥作为参数步骤如下: 1、 用OpenMSPrimitiveProviderAES打开算法提供者 2、 用CreateSymmetricKey_AES_CBC创建个密钥或用CreateSymmetricKey_SHA1_Hash导入个密钥 3、 获取相关文件缓冲区 4、 通过Crypt执行加解密操作输出中间文件并通过CryptLastByte获得最终文件 5、 保存加密数据到输出文件 OpenMSPrimitiveProviderAES思路方法打开个到AES提供者句柄 bool CMyCNGCryptFile::OpenMSPrimitiveProviderAES { NTSTATUS ntStatus = STATUS_UNSUCCESSFUL; ntStatus = BCryptOpenAlgorithmProvider( &m_hAesAlg, BCRYPT_AES_ALGORITHM, NULL, 0); switch (ntStatus) { STATUS_SUCCESS: true; STATUS_INVALID_PARAMETER: STATUS_NO_MEMORY: default: //... ... } false; } CreateSymmetricKey_AES_CBC思路方法获取个密钥并把它作为个静态常数BYTE变量rgbAES128Key存储在中第步通过BCryptGetProperty取得算法属性接着用算法提供者句柄得到算法实现细节如密钥大小及IV大小;第 2步把它分配在堆中并通过BCryptSetProperty修改算法属性此处假定要使用BCRYPT_CHAIN_MODE_CBC我们将AES算法BCRYPT_CHAINING_MODE属性设为BCRYPT_CHAIN_MODE_CBC现在我们就可通过BCryptGenerateSymmetricKey来创建个短暂密钥了 bool CMyCNGCryptFile::CreateSymmetricKey_AES_CBC(DWORD &cbKeyObject, DWORD &cbIV ) { NTSTATUS ntStatus = STATUS_UNSUCCESSFUL; DWORD cbData = 0; cbKeyObject = 0; cbIV = 0; ntStatus = BCryptGetProperty(m_hAesAlg, BCRYPT_OBJECT_LENGTH, (PBYTE)&cbKeyObject, (DWORD), &cbData, 0); ... m_pbKeyObject = (PBYTE)HeapAlloc (GetProcessHeap , 0, cbKeyObject); ... ntStatus = BCryptGetProperty( m_hAesAlg, BCRYPT_BLOCK_LENGTH, (PBYTE)&cbIV, (DWORD), &cbData, 0); ... m_pbIV= (PBYTE) HeapAlloc (GetProcessHeap , 0, cbIV); memcpy(m_pbIV, rgbIV, cbIV); ntStatus = BCryptSetProperty(m_hAesAlg, BCRYPT_CHAINING_MODE, (PBYTE)BCRYPT_CHAIN_MODE_CBC, (BCRYPT_CHAIN_MODE_CBC), 0); ... ntStatus = BCryptGenerateSymmetricKey(m_hAesAlg, &m_hKey, m_pbKeyObject, cbKeyObject, (PBYTE)rgbAES128Key, (rgbAES128Key), 0); ... true; } CreateSymmetricKey_SHA1_Hash思路方法从用户处获取个密钥第步通过BCryptOpenAlgorithmProvider打开个新算法SHA1使用SHA1是提供者支持我们后面要用到哈希接口接下来通过BCryptGetProperty得到算法属性再使用算法提供者句柄得到算法实现细节如密钥大小及哈希大小的后再把它分配在堆中通过BCryptCreateHash为密钥创建哈希对象;第 2步使用BCryptHashData对数据缓冲区执行单向哈希并得到要用于BCryptHashData哈希值为此使用了BCryptFinishHash现在就可通过BCryptSetProperty修改算法属性像上面样把AES算法BCRYPT_CHAINING_MODE属性设为BCRYPT_CHAIN_MODE_CBC最终将通过BCryptGenerateSymmetricKey创建个短暂密钥 bool CMyCNGCryptFile::CreateSymmetricKey_SHA1_Hash(PCWSTR pwszText, DWORD cbKeyObject) { NTSTATUS ntStatus = STATUS_SUCCESS; BCRYPT_KEY_HANDLE hKey = NULL; DWORD cbHashObject, cbResult; BYTE rgbHash[20]; DWORD cbData = 0; ntStatus = BCryptOpenAlgorithmProvider(&m_hHashAlg, BCRYPT_SHA1_ALGORITHM,NULL,0); ... ntStatus = BCryptGetProperty(m_hAesAlg, BCRYPT_OBJECT_LENGTH, (PBYTE)&cbKeyObject, (DWORD), &cbData, 0); ... ntStatus = BCryptGetProperty( m_hHashAlg,BCRYPT_OBJECT_LENGTH, (PBYTE) &cbHashObject,(DWORD),&cbResult,0); ... ntStatus = BCryptCreateHash(m_hHashAlg, &m_hHash, m_pbHashObject, cbHashObject, NULL, 0, 0 ); ntStatus = BCryptHashData( m_hHash, (PBYTE)pwszText, (ULONG)wcslen( pwszText), 0); ntStatus = BCryptFinishHash( m_hHash, rgbHash, (rgbHash), 0); ... ntStatus = BCryptGenerateSymmetricKey( m_hAesAlg, &hKey, m_pbKeyObject, cbKeyObject, rgbHash, SYMM_KEY_SIZE_SECRET, 0 ); ... true; } Crypt思路方法通过BCryptEncrypt和BCryptDecrypt执行加解密操作另外使用了相同长度密文来加密数据 bool CMyCNGCryptFile::Crypt(bool bEncrypt,PUCHAR pbufFileToOpen, ULONG iBytesRead, ULONG cbIV, PBYTE pbufFileToSave, DWORD& iBufToSave) { NTSTATUS ntStatus =STATUS_UNSUCCESSFUL; DWORD cbCipherText = 0; ( bEncrypt ) ntStatus = BCryptEncrypt(m_hKey, pbufFileToOpen, iBytesRead, NULL, m_pbIV, cbIV, pbufFileToSave, iBytesRead, &iBufToSave, 0); ntStatus = BCryptDecrypt(m_hKey, pbufFileToOpen, iBytesRead, NULL, m_pbIV, cbIV, pbufFileToSave, iBytesRead, &iBufToSave, 0); ... false; } CryptLastByte思路方法使用了区别长度密文来加密数据此处了BCryptEncrypt或BCryptDecrypt两次第次是为了得到加密数据大小第 2次是得到密文 bool CMyCNGCryptFile::CryptLastByte(bool bEncrypt,PUCHAR pbufFileToOpen, ULONG iBytesRead, ULONG cbIV, PBYTE pbufFileToSave, DWORD& iBufToSave) { NTSTATUS ntStatus= STATUS_UNSUCCESSFUL; DWORD cbCipherText = 0; (bEncrypt) { ntStatus = BCryptEncrypt(m_hKey, pbufFileToOpen, iBytesRead, NULL, m_pbIV, cbIV, NULL, 0, &cbCipherText, BCRYPT_BLOCK_PADDING); ... ntStatus = BCryptEncrypt( m_hKey, pbufFileToOpen, iBytesRead, NULL, m_pbIV, cbIV, pbufFileToSave, cbCipherText, &cbCipherText,BCRYPT_BLOCK_PADDING); iBufToSave = cbCipherText; ... } { ntStatus = BCryptDecrypt( m_hKey, pbufFileToOpen, iBytesRead, NULL, m_pbIV, cbIV, NULL, 0, &cbCipherText, BCRYPT_BLOCK_PADDING); ... ntStatus = BCryptDecrypt( m_hKey, pbufFileToOpen, iBytesRead, NULL, m_pbIV, cbIV, pbufFileToSave, cbCipherText, &cbCipherText, BCRYPT_BLOCK_PADDING); ... } false; } EnumProviders思路方法返回当前计算机上已安装提供者BCryptEnumRegisteredProviders以获取有关已注册提供者信息从pProviders中枚举提供者其为个PCRYPT_PROVIDERS结构 bool CMyCNGCryptFile::EnumProviders(CStringList *lstRegisteredProviders) { ... ntStatus = BCryptEnumRegisteredProviders(&cbBuffer, &pProviders); ... for ( DWORD i = 0; i < pProviders->cProviders; i) { sProvider.Format(_T("%s\n"), pProviders->rgpszProviders[i]); lstRegisteredProviders->AddHead(sProvider); } (pProviders != NULL) { BCryptFreeBuffer(pProviders); } true; } ~CMyCNGCryptFile析构关闭算法提供者删除所有指针以防内存泄漏并销毁密钥哈希此处了BCryptCloseAlgorithmProvider来关闭算法提供者BCryptDestroyKey用于销毁密钥BCryptDestroyHash用于销毁哈希最后从PCRYPT_PROVIDERS结构pProviders中枚举提供者 CMyCNGCryptFile::~CMyCNGCryptFile { BCryptCloseAlgorithmProvider(m_hAesAlg,0); BCryptDestroyKey(m_hKey); HeapFree(GetProcessHeap, 0, m_pbKeyObject); HeapFree(GetProcessHeap, 0, m_pbIV); //Hash BCryptDestroyHash(m_hHash); free(m_pbHashObject); BCryptCloseAlgorithmProvider(m_hHashAlg,0); } 0
相关文章
读者评论发表评论 |