📄 crypto.cpp
字号:
////////////////////////////////////////////////////////////////////////////////
//
// Title: Cryptography Object
// File: TSDocCrypto.cpp
// Author: Chad Slater
// Date: January 2001
//
// Current Encrypted File Binary Format:
//---------------------------------------
//
// +-----------+
// | 4 BYTES | <-- Binary format version (reserved)
// |-----------|
// | 4 BYTES | <-- Size of the private key
// |-----------|
// | |
// | VARIABLE | <-- Private key (typically ~76 bytes)
// | SIZE |
// |___________|
// | |
// | VARIABLE |
// | SIZE | <-- Encrypted data
// | |
// |-----------|
// | EOF |
// |___________|
//
//
// Current String Binary Format (In-memory Encryption):
//-----------------------------------------------------
//
// +---------------+
// | BASE64 ENCODED|<---- Base64 Encoded BSTR
// | WRAPPER |
// | +-----------+ |
// | | 4 BYTES |<---- Binary format version (reserved)
// | |-----------| |
// | | 4 BYTES |<---- Size of the private key
// | |-----------| |
// | | | |
// | | VARIABLE |<---- Private key (typically ~76 bytes)
// | | SIZE | |
// | |-----------| |
// | | 4 BYTES |<---- Size of the encrypted data
// | |-----------| |
// | | | |
// | | VARIABLE | |
// | | SIZE |<---- Encrypted data
// | |___________| |
// |_______________|
//
//
// Revision History:
// ---------------------------------------------------------------------
//
// cslater 01/26/2001 Initial revision
// cslater 01/29/2001 Implemented EncryptDoc and DecryptDoc
// cslater 01/30/2001 Initial attempt at in-memory encryption with
// 128-bit encryption + Base64 encoding (failed...)
// cslater 01/31/2001 Fixed the in-memory encryption algorithms so they
// actually work (royal pain in the neck)
// cslater 02/01/2001 Fixed memory leaks
// cslater 02/02/2001 Added Base64EncodeFile and Base64DecodeFile
// cslater 02/06/2001 Added Base64EncodeFileToString and
// Base64DecodeFileToString
//
//
///////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "Base64Helper.h"
#include "Common.h"
#include "Crypto.h"
// Types
typedef BYTE* LPBYTE;
// Algorithm to use for encryption
#define FILE_ENCRYPT_ALGORITHM CALG_RC2
#define INMEMORY_ENCRYPT_ALGORITHM CALG_RC4
#define HASHING_ALGORITHM CALG_MD5
// Key container name - Unique per application
#define CRYPTO_KEY_CONTAINER_NAME _T("ICRYPTO_VERSION_1_0")
// Binary file format version (encrypted files)
#define INVALID_FORMAT_VERSION 0xFFFFFFFF
#define BINARY_FORMAT_MAJOR_VERSION ((WORD)0x0001)
#define BINARY_FORMAT_MINOR_VERSION ((WORD)0x0000)
#define FILE_BINARY_FORMAT_VERSION MAKELONG(BINARY_FORMAT_MINOR_VERSION,\
BINARY_FORMAT_MAJOR_VERSION)
#define INMEMORY_FORMAT_VERSION MAKELONG(BINARY_FORMAT_MINOR_VERSION,\
BINARY_FORMAT_MAJOR_VERSION)
// General defines
#define FILE_INTERMEDIATE_FILENAME "INTERMEDIATE.CRP"
#define FILE_READBYTES 0x00000200
#define SIZE_VERSION sizeof(DWORD)
#define SIZE_PRIVATEKEY_SIZE sizeof(DWORD)
#define SIZE_ENCRYPTED_DATA sizeof(DWORD)
// General macros
#define VERIFY_MALLOC(lpData) {\
if(!lpData)\
nStringID=IDS_ERROR_OUTOFMEMORY,\
THROW_HRESULT( E_OUTOFMEMORY );\
}
#define CRYPTO_OUTPUT_DEBUGSTRING(nStringID) {\
{\
TCHAR szMessage[ MAX_MSG ] = { 0 }; \
if(::LoadString( _Module.GetResourceInstance(),\
nStringID,\
szMessage,\
MAX_MSG ) ) \
::OutputDebugString( szMessage ); \
}\
}
CCrypto::
CCrypto()
:
m_hContext( NULL ),
m_lpDigitalSignature( NULL ),
m_dwDigitalSignatureLen( 0 ),
m_bstrContainerName( CRYPTO_KEY_CONTAINER_NAME )
{}
CCrypto::
~CCrypto()
{
if( m_hContext )
{
CryptReleaseContext( m_hContext, 0 );
m_hContext = NULL;
}
ClearDigitalSignature();
}
STDMETHODIMP CCrypto::
InterfaceSupportsErrorInfo( REFIID riid )
{
static const IID* arr[] = { &IID_ICrypto };
for (int i=0; i < sizeof(arr) / sizeof(arr[0]); i++)
{
if( ::InlineIsEqualGUID( *arr[i], riid ) )
return S_OK;
}
return S_FALSE;
}
STDMETHODIMP CCrypto::
get_DigitalSignature( BSTR* pVal )
{
HRESULT hr = E_FAIL;
HGLOBAL hDigSig = NULL;
LPBYTE lpEncodedBytes = NULL;
ATLASSERT( pVal );
if( pVal )
{
if( m_lpDigitalSignature &&
m_dwDigitalSignatureLen > 0 )
{
PBYTE lpEncodedDigSig = NULL;
DWORD dwEncodedDigSig = 0;
CBase64Helper Base64;
// Encode the digital signature
dwEncodedDigSig = Base64.Base64Encoder( m_lpDigitalSignature,
m_dwDigitalSignatureLen,
&hDigSig );
lpEncodedDigSig = (LPBYTE)GlobalLock( hDigSig );
ATLASSERT( lpEncodedDigSig );
if( lpEncodedDigSig )
{
// Convert to a zero-terminated string
lpEncodedBytes = (LPBYTE)malloc( sizeof(BYTE) * dwEncodedDigSig + 1 );
if( lpEncodedBytes )
{
USES_CONVERSION;
// Copy out to the caller
memcpy( lpEncodedBytes, lpEncodedDigSig, dwEncodedDigSig );
lpEncodedBytes[ dwEncodedDigSig ] = '\0';
*pVal = ::SysAllocString( A2W((char*)lpEncodedBytes) );
if( (*pVal) &&
::SysStringLen( *pVal ) > 0 )
hr = S_OK;
else
hr = Error( IDS_ERROR_OUTOFMEMORY, IID_ICrypto, E_OUTOFMEMORY );
}
else
hr = Error( IDS_ERROR_OUTOFMEMORY, IID_ICrypto, E_OUTOFMEMORY );
}
else
hr = Error( IDS_ERROR_OUTOFMEMORY, IID_ICrypto, E_OUTOFMEMORY );
}
else
hr = Error( IDS_ERROR_DIGITALSIGNATURE_NOTAVAILABLE,
IID_ICrypto, E_FAIL );
}
else
hr = Error( IDS_ERROR_INVALID_ARG, IID_ICrypto, E_INVALIDARG );
if( hDigSig )
GlobalFree( hDigSig );
SAFE_MALLOC_FREE(lpEncodedBytes);
return hr;
}
STDMETHODIMP CCrypto::
get_ContainerName( BSTR *pVal )
{
return m_bstrContainerName.CopyTo( pVal );
}
STDMETHODIMP CCrypto::
put_ContainerName( BSTR newVal )
{
m_bstrContainerName = newVal;
return S_OK;
}
STDMETHODIMP CCrypto::
VerifyDigitalSignature( BSTR bstrDigitalSig, BOOL* pbMatches )
{
HRESULT hr = S_OK;
CComBSTR bstrSrcDigSig( bstrDigitalSig );
CComBSTR bstrDigSig;
ATLASSERT( pbMatches != NULL );
if( pbMatches != NULL )
{
if( m_lpDigitalSignature &&
m_dwDigitalSignatureLen > 0 )
{
// Get the encoded string version of the digital signature
hr = get_DigitalSignature( &bstrDigSig );
if( SUCCEEDED( hr ) )
*pbMatches = ( bstrDigSig == bstrDigitalSig );
}
else
hr = Error( IDS_ERROR_DIGITALSIGNATURE_NOTAVAILABLE,
IID_ICrypto, E_FAIL );
}
else
hr = Error( IDS_ERROR_INVALID_ARG, IID_ICrypto, E_INVALIDARG );
return hr;
}
STDMETHODIMP CCrypto::
EncryptDoc( BSTR bstrSrc,
VARIANT varDestination )
{
USES_CONVERSION;
USES_CHECKHR_MSG( IID_ICrypto );
HRESULT hr = S_OK;
HCRYPTKEY hPrivateKey = NULL;
HCRYPTHASH hDigSigHash = NULL;
LPBYTE lpPrivateKey = NULL;
LPBYTE lpData = NULL;
FILE* pSrcFile = NULL;
FILE* pDestinationFile = NULL;
BOOL bSrcIsDestination = PARAM_IS_MISSING( varDestination );
try
{
pSrcFile = fopen( W2A(bstrSrc), "rb" );
// Open destination with intentions of destroying existing contents
if( pSrcFile )
pDestinationFile = bSrcIsDestination ?
fopen( FILE_INTERMEDIATE_FILENAME, "w+b" ) :
fopen( W2A(varDestination.bstrVal), "w+b" );
ATLASSERT( pSrcFile != NULL );
ATLASSERT( pDestinationFile != NULL );
// Make sure the files opened
if( pSrcFile == NULL ||
pDestinationFile == NULL )
nStringID = IDS_ERROR_ENCRYPTFILE_FILEOPENFAILED,
THROW_HRESULT( E_FAIL );
if( !WriteFileFormatVersion( pDestinationFile ) )
nStringID = IDS_ERROR_ENCRYPT_WRITEFILEFORMATVERSION,
THROW_HRESULT( E_FAIL );
// Write the private key to the destination file
ClearDigitalSignature();
if( Initialize() &&
WritePrivateKey( pDestinationFile,
hPrivateKey ) )
{
lpData = (LPBYTE)malloc( FILE_READBYTES * sizeof( BYTE ) );
VERIFY_MALLOC( lpData );
// Create the hash for digital signature
if( !CryptCreateHash( m_hContext,
HASHING_ALGORITHM, 0, 0,
&hDigSigHash ) )
nStringID = IDS_ERROR_HASHCREATE_FAILED,
THROW_HRESULT( E_FAIL );
// Read in the data from the source file, encrypt it and write to the destination
do
{
DWORD dwCount = fread( lpData,
sizeof(BYTE),
FILE_READBYTES,
pSrcFile );
if( ferror( pSrcFile ) )
nStringID = IDS_ERROR_ENCRYPT_READING_SOURCE,
THROW_HRESULT( E_FAIL );
// If encryption fails, give some useful information back to caller
if( !CryptEncrypt( hPrivateKey,
hDigSigHash,
feof(pSrcFile),
0, lpData,
&dwCount, FILE_READBYTES ) )
nStringID = IDS_ERROR_ENCRYPT_ENCRYPTION_FAILED,
THROW_HRESULT( E_FAIL );
// Write encrypted data to the destination file
fwrite( lpData,
sizeof(BYTE),
dwCount,
pDestinationFile );
if( ferror( pDestinationFile ) )
nStringID = IDS_ERROR_ENCRYPT_WRITETODESTINATION_FAILED,
THROW_HRESULT( E_FAIL );
}
while( !feof( pSrcFile ) );
fflush( pDestinationFile );
if( !DigitallySignHash( hDigSigHash ) )
nStringID = IDS_ERROR_ENCRYPT_SIGNHASH_FAILED,
THROW_HRESULT( E_FAIL );
}
else
nStringID = IDS_ERROR_INITIALIZATION_FAILED,
THROW_HRESULT( E_FAIL );
}
catch( HRESULT _hr )
{
CATCH_FAILED_HR(_hr);
}
////////////////////
// Cleanup
if( hPrivateKey )
CryptDestroyKey( hPrivateKey );
SAFE_MALLOC_FREE( lpPrivateKey );
if( pSrcFile )
fclose( pSrcFile );
if( pDestinationFile )
fclose( pDestinationFile );
SAFE_MALLOC_FREE( lpData );
if( hDigSigHash )
CryptDestroyHash( hDigSigHash );
// Caller wants to overwrite src - Copy Destination to Source
if( bSrcIsDestination )
{
// CopyFile fails if file is readonly
SetFileAttributes( W2T(bstrSrc), FILE_ATTRIBUTE_NORMAL );
if( !CopyFile( A2T(FILE_INTERMEDIATE_FILENAME), W2T(bstrSrc), FALSE ) )
hr = Error( IDS_ERROR_DECRYPT_COPYDESTINATIONTOSOURCE_FAILED,
IID_ICrypto, E_FAIL );
}
// Delete the intermediate file - if it exists
_unlink( FILE_INTERMEDIATE_FILENAME );
return hr;
}
STDMETHODIMP CCrypto::
DecryptDoc( BSTR bstrSrc,
VARIANT varDestination )
{
USES_CONVERSION;
USES_CHECKHR_MSG( IID_ICrypto );
HRESULT hr = S_OK;
HCRYPTKEY hPrivateKey = NULL;
HCRYPTHASH hDigSigHash = NULL;
LPBYTE lpData = NULL;
FILE* pSrcFile = NULL;
FILE* pDestinationFile = NULL;
BOOL bSrcIsDestination = PARAM_IS_MISSING( varDestination );
try
{
pSrcFile = fopen( W2A(bstrSrc), "rb" );
// Open destination with intentions of destroying existing contents
if( pSrcFile )
pDestinationFile = bSrcIsDestination ?
fopen( FILE_INTERMEDIATE_FILENAME, "w+b" ) :
fopen( W2A(varDestination.bstrVal), "w+b" );
ATLASSERT( pSrcFile != NULL );
ATLASSERT( pDestinationFile != NULL );
// Make sure the files opened
if( pSrcFile == NULL ||
pDestinationFile == NULL )
nStringID = IDS_ERROR_DECRYPTFILE_FILEOPENFAILED,
THROW_HRESULT( E_FAIL );
// Read the version stamp and make sure its a version that we can read
if( !ReadFileFormatVersion( pSrcFile ) )
nStringID = IDS_ERROR_DECRYPTFILE_READINGFILEVERSION,
THROW_HRESULT( E_FAIL );
// Read the private key and import into CSP
ClearDigitalSignature();
if( Initialize() &&
ReadPrivateKey( pSrcFile, hPrivateKey ) )
{
lpData = (LPBYTE)malloc( FILE_READBYTES * sizeof( BYTE ) );
VERIFY_MALLOC( lpData );
// Create the hash for digital signature
if( !CryptCreateHash( m_hContext,
HASHING_ALGORITHM, 0, 0,
&hDigSigHash ) )
nStringID = IDS_ERROR_HASHCREATE_FAILED,
THROW_HRESULT( E_FAIL );
// Read in the data from the source file, encrypt it and write to the destination
do
{
DWORD dwCount = fread( lpData,
sizeof(BYTE),
FILE_READBYTES,
pSrcFile );
if( ferror( pSrcFile ) )
nStringID = IDS_ERROR_DECRYPT_READING_SOURCE,
THROW_HRESULT( E_FAIL );
// If encryption fails, give some useful information back to caller
if( !CryptDecrypt( hPrivateKey,
hDigSigHash,
feof(pSrcFile),
0, lpData,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -