Интерфейс:
// WinCrypto.h - interface of the CWinCrypto class
// Copyright (c) 2004-2008 by Elijah Zarezky,
// All rights reserved.
#if !defined(__WinCrypto_h)
#define __WinCrypto_h
#if defined(_MSC_VER) && (_MSC_VER > 1000)
#pragma once
#endif // _MSC_VER
#if !defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x0400)
#error this code uses features only available under Windows 98/NT4 or later
#endif // _WIN32_WINNT
#if !defined(__AFXTEMPL_H__)
#pragma message(__FILE__ " : put <afxtempl.h> in your PCH to speed up compilation")
#include <afxtempl.h>
#endif // __AFXTEMPL_H__
#if !defined(__WINCRYPT_H__)
#pragma message(__FILE__ " : put <wincrypt.h> in your PCH to speed up compilation")
#include <wincrypt.h>
#endif // __WINCRYPT_H__
class CWinCrypto: public CObject
{
DECLARE_DYNAMIC(CWinCrypto)
// construction/destruction
public:
CWinCrypto(LPCTSTR pszContainer, ALG_ID algID = CALG_DES, LPCTSTR pszPassword = NULL);
virtual ~CWinCrypto(void);
// copying/assignment - not allowed and thus not implemented
private:
CWinCrypto(const CWinCrypto& src);
CWinCrypto& operator =(const CWinCrypto& src);
// operations
public:
void GenerateKey(ALG_ID algID = CALG_DES, LPCTSTR pszPassword = NULL);
DWORD EncryptString(BSTR bstrSrc, CArray<BYTE, BYTE>& arrDest);
DWORD DecryptString(CArray<BYTE, BYTE>& arrSrc, BSTR* pbstrDest);
// attributes
public:
HCRYPTPROV m_hContext;
HCRYPTKEY m_hKey;
// implementation helpers
private:
DWORD AcquireContext(LPCTSTR pszContainer);
// diagnostic services
#if defined(_DEBUG)
public:
virtual void AssertValid(void) const;
virtual void Dump(CDumpContext& dumpCtx) const;
#endif
};
#endif // __WinCrypto_h
Реализация:
// WinCrypto.cpp - implementation of the CWinCrypto class
// Copyright (c) 2004-2008 by Elijah Zarezky,
// All rights reserved.
#include "WinCrypto.h"
#include "Win32Error.h"
#if defined(__INTEL_COMPILER)
// warning #68: integer conversion resulted in a change of sign
#pragma warning(disable: 68)
// remark #279: controlling expression is constant
#pragma warning(disable: 279)
#endif // __INTEL_COMPILER
#if defined(_DEBUG)
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#define new DEBUG_NEW
#endif // _DEBUG
// object model
IMPLEMENT_DYNAMIC(CWinCrypto, CObject)
CWinCrypto::CWinCrypto(LPCTSTR pszContainer, ALG_ID algID, LPCTSTR pszPassword):
m_hContext(NULL),
m_hKey(NULL)
{
DWORD dwErrCode;
// precondition
ASSERT(AfxIsValidString(pszContainer));
if ((dwErrCode = AcquireContext(pszContainer)) != ERROR_SUCCESS)
{
throw new CWin32Error(dwErrCode);
}
else try
{
GenerateKey(algID, pszPassword);
}
catch (CWin32Error*)
{
if (m_hKey != NULL)
{
::CryptDestroyKey(m_hKey);
m_hKey = NULL;
}
::CryptReleaseContext(m_hContext, 0);
m_hContext = NULL;
THROW_LAST();
}
}
CWinCrypto::~CWinCrypto(void)
{
// simple clean-up
::CryptDestroyKey(m_hKey);
::CryptReleaseContext(m_hContext, 0);
}
void CWinCrypto::GenerateKey(ALG_ID algID, LPCTSTR pszPassword)
{
HW_PROFILE_INFO hwProfileInfo;
DWORD dwErrCode;
// precondition
ASSERT(m_hContext != NULL);
// destroy current key (if any)
if (m_hKey != NULL)
{
::CryptDestroyKey(m_hKey);
m_hKey = NULL;
}
if (pszPassword == NULL || *pszPassword == 0)
{
// obtain default password
::GetCurrentHwProfile(&hwProfileInfo);
pszPassword = hwProfileInfo.szHwProfileGuid;
}
ASSERT(AfxIsValidString(pszPassword));
// try to create a hash object
HCRYPTHASH hHash = NULL;
if (!::CryptCreateHash(m_hContext, CALG_MD5, NULL, 0, &hHash))
{
dwErrCode = ::GetLastError();
throw new CWin32Error(dwErrCode);
}
ASSERT(hHash != NULL);
// hash the password
const BYTE* pbKeyData = reinterpret_cast<const BYTE*>(pszPassword);
int nDataLen = ::lstrlen(pszPassword) * sizeof(TCHAR);
if (!::CryptHashData(hHash, pbKeyData, nDataLen, 0))
{
dwErrCode = ::GetLastError();
::CryptDestroyHash(hHash);
throw new CWin32Error(dwErrCode);
}
// derive a session key from the hash object
if (!::CryptDeriveKey(m_hContext, algID, hHash, 0, &m_hKey))
{
dwErrCode = ::GetLastError();
::CryptDestroyHash(hHash);
throw new CWin32Error(dwErrCode);
}
ASSERT(m_hKey != NULL);
// clean-up
::CryptDestroyHash(hHash);
}
DWORD CWinCrypto::EncryptString(BSTR bstrSrc, CArray<BYTE, BYTE>& arrDest)
{
DWORD cbBufSize;
// precondition
ASSERT(m_hContext != NULL);
ASSERT(m_hKey != NULL);
ASSERT(bstrSrc != NULL);
ASSERT(::SysStringLen(bstrSrc) > 0);
DWORD cbDataSize = cbBufSize = ::SysStringByteLen(bstrSrc);
if (::CryptEncrypt(m_hKey, NULL, TRUE, 0, NULL, &cbBufSize, 0))
{
arrDest.SetSize(cbBufSize);
BYTE* pbData = arrDest.GetData();
memcpy(pbData, bstrSrc, cbDataSize);
if (::CryptEncrypt(m_hKey, NULL, TRUE, 0, pbData, &cbDataSize, cbBufSize))
{
ASSERT(cbDataSize == cbBufSize);
return (cbDataSize);
}
}
throw new CWin32Error(::GetLastError());
}
DWORD CWinCrypto::DecryptString(CArray<BYTE, BYTE>& arrSrc, BSTR* pbstrDest)
{
// precondition
ASSERT(m_hContext != NULL);
ASSERT(m_hKey != NULL);
ASSERT(arrSrc.GetSize() > 0);
ASSERT(pbstrDest != NULL);
DWORD cbBufSize = arrSrc.GetSize();
BYTE* pbData = arrSrc.GetData();
if (::CryptDecrypt(m_hKey, NULL, TRUE, 0, pbData, &cbBufSize))
{
ASSERT(cbBufSize > 0);
cbBufSize /= sizeof(OLECHAR);
*pbstrDest = ::SysAllocStringLen(reinterpret_cast<OLECHAR*>(pbData), cbBufSize);
return (cbBufSize);
}
else
{
throw new CWin32Error(::GetLastError());
}
}
DWORD CWinCrypto::AcquireContext(LPCTSTR pszContainer)
{
DWORD dwErrCode;
// precondition
ASSERT(AfxIsValidString(pszContainer));
if (::CryptAcquireContext(&m_hContext, pszContainer, NULL, PROV_RSA_FULL, 0))
{
// successfully acquired
dwErrCode = ERROR_SUCCESS;
}
// if the key container doesn't exist...
else if ((dwErrCode = ::GetLastError()) == NTE_BAD_KEYSET)
{
// ...then try to create it for the first time
if (::CryptAcquireContext(&m_hContext, pszContainer, NULL, PROV_RSA_FULL, CRYPT_NEWKEYSET))
{
// successfully created
dwErrCode = ERROR_SUCCESS;
}
else
{
dwErrCode = ::GetLastError();
}
}
return (dwErrCode);
}
#if defined(_DEBUG)
void CWinCrypto::AssertValid(void) const
{
// first perform inherited validity check...
CObject::AssertValid();
// ...and then verify own state as well
ASSERT(m_hContext != NULL);
ASSERT(m_hKey != NULL);
}
void CWinCrypto::Dump(CDumpContext& dumpCtx) const
{
try
{
// first invoke inherited dumper...
CObject::Dump(dumpCtx);
// ...and then dump own unique members
dumpCtx << "m_hContext = " << m_hContext << "\n";
dumpCtx << "m_hKey = " << m_hKey;
}
catch (CFileException* pXcpt)
{
pXcpt->ReportError();
pXcpt->Delete();
}
}
#endif // _DEBUG
// import libraries
#pragma comment(lib, "advapi32.lib")
#pragma comment(lib, "oleaut32.lib")
Пример использования:
CArray<BYTE, BYTE> arrEncTest;
try
{
CWinCrypto winCrypto(AfxGetAppName());
BSTR bstrTest = ::SysAllocString(OLESTR("test"));
winCrypto.EncryptString(bstrTest, arrEncTest);
::SysFreeString(bstrTest);
}
catch (CWin32Error* pXcpt)
{
pXcpt->ReportError();
delete pXcpt;
}
|