⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 md5filecalculator.cpp

📁 利用Windows API来计算MD5的MFC例程.计算MD5时主要用到了CryptAcquireContext、CryptCreateHash两个API
💻 CPP
字号:
//*****************************************************************************
// FILE: MD5FileCalculator.cpp
// DESC: Header for CMD5FileCalculator class.
//
// By Giovanni Dicanio <giovanni.dicanio@gmail.com>
// 2008, September 26th
//*****************************************************************************



//=============================================================================
//                              INCLUDES
//=============================================================================

#include "stdafx.h"
#include "MD5FileCalculator.h"      // Module header



//=============================================================================
//                          METHOD IMPLEMENTATIONS
//=============================================================================


CMD5FileCalculator::CMD5FileCalculator( LPCTSTR filename, DWORD chunkSize )
    : m_initOK( FALSE ),            // initialization not done yet
    m_digestReady( FALSE ),         // no MD5 digest calculated yet
    m_fileSize( 0 ),                // no info on file size
    m_hFile( INVALID_HANDLE_VALUE ),// no file open yet
    m_hCryptProv( NULL ),           // no CSP acquired
    m_hCryptHash( NULL ),           // no hash object created
    m_readBuffer( NULL ),           // buffer for hashing
    m_readBufferSize( 0 ),          // no chunk allocated yet
    m_processedBytes( 0 )           // nothing processed yet
{
    // File name must be not null and not empty
    ATLASSERT( filename != NULL );
    ATLASSERT( *filename != TEXT('\0') );

    // Store filename
    m_fileName = filename;

    // Try opening the file
    m_hFile = ::CreateFile( 
        filename,           // file name
        GENERIC_READ,       // request reading access to file
        FILE_SHARE_READ,    // enables subsequent open operations on a file or device to request read access
        NULL,               // security attributes unused
        OPEN_EXISTING,      // opens file only if it exists
        FILE_FLAG_SEQUENTIAL_SCAN, // access is intended to be sequential from beginning to end
        NULL                // no template used
        );
    if ( m_hFile == INVALID_HANDLE_VALUE )
    {
        // Error in opening file
        return;
    }

    // Get file size
    LARGE_INTEGER fileSize;
    if ( ! ::GetFileSizeEx( m_hFile, &fileSize) )
    {
        // Error
        Cleanup();
        return;
    }
    m_fileSize = fileSize.QuadPart;

    // Acquire a handler to a CSP (Cryptographic Service Provider)
    if ( ! ::CryptAcquireContext(
        &m_hCryptProv,  // variable to hold the returned handle
        NULL,           // use default key container
        NULL,           // use default provider 
        PROV_RSA_FULL,  // type of context to acquire
        CRYPT_VERIFYCONTEXT | CRYPT_MACHINE_KEYSET // good flags for hashing
        ) )
    {
        // Error
        Cleanup();
        return;
    }

    // Acquire handler to hash object
    if ( ! ::CryptCreateHash(
        m_hCryptProv,   // handle to CSP obtained earlier
        CALG_MD5,       // hashing algorithm
        0,              // non-keyed hash
        0,              // should be 0
        &m_hCryptHash   // handle value to be retrieved
        ) )
    {
        // Error
        Cleanup();
        return;
    }

    // Allocate read buffer
    ATLASSERT( chunkSize > 0 );
    m_readBufferSize = chunkSize;
    m_readBuffer = new BYTE[ m_readBufferSize ];

    // Object initialization successful
    m_initOK = TRUE;
}


void CMD5FileCalculator::Cleanup()
{
    // Clear digest string
    m_digestReady = FALSE;
    m_digest.Empty();

    // Clear file size info
    m_fileSize = 0;

    // Nothing processed
    m_processedBytes = 0;



    // Cleanup hash handler
    if ( m_hCryptHash != NULL )
    {
        ::CryptDestroyHash( m_hCryptHash );
        m_hCryptHash = NULL;
    }

    // Cleanup CSP handler
    if ( m_hCryptProv != NULL )
    {
        ::CryptReleaseContext( m_hCryptProv, 0 );
        m_hCryptProv = NULL;
    }

    // Close file
    if ( m_hFile != INVALID_HANDLE_VALUE )
    {
        ::CloseHandle( m_hFile );
        m_hFile = INVALID_HANDLE_VALUE;
    }

    // Cleanup read buffer
    if ( m_readBuffer != NULL )
    {
        delete [] m_readBuffer;
        m_readBuffer = NULL;

        m_readBufferSize = 0;
    }


    // Object is no more initialized
    m_initOK = FALSE;
}


CMD5FileCalculator::~CMD5FileCalculator()
{
    Cleanup();
}


BOOL CMD5FileCalculator::HashMore()
{
    // Initialization must be successful
    ATLASSERT( m_initOK );

    // Hash must not be available when this method is called
    ATLASSERT( ! m_digestReady );

    // Read a new chunk from file
    DWORD readBytes = 0;
    BOOL success = ::ReadFile( m_hFile, m_readBuffer, m_readBufferSize, &readBytes, NULL );
    if ( ! success )
    {
        // Stop: Read error
        return FALSE;
    }

    // Read was successful

    // If there is no more data, it means that we can finalize the hash computation
    if ( readBytes == 0 )
    {
        BYTE hashValue[ 128 ]; // 16 bytes are fine for MD5 hash, but just make a bigger buffer...
        static const int md5HashByteCount = 16; // 16 bytes for MD5 hash
        DWORD hashValueSize = md5HashByteCount; 

        // Get hash value
        if ( ! ::CryptGetHashParam(
            m_hCryptHash,       // Handle to hash object
            HP_HASHVAL,         // Get hash value
            hashValue,          // Buffer to hold hash value
            &hashValueSize,     // Length of data
            0) )                // Must be zero
        {
            // Error
            return FALSE;
        }

        // Convert digest bytes to a string (with bytes represented in hex),
        // and save digest string in data member
        m_digest = ConvertMD5DigestToString( hashValue );

        // Digest string ready
        m_digestReady = TRUE;

        // Stop looping - job well done
        return FALSE;
    }

    // We have more bytes to process
    ATLASSERT( readBytes != 0 );

    // Update processed byte count
    m_processedBytes += readBytes;

    success = ::CryptHashData( m_hCryptHash, m_readBuffer, readBytes, 0 );
    return success; // stop looping on error, else continue looping
}


CString CMD5FileCalculator::ConvertMD5DigestToString( const BYTE * hashValue )
{
    // Check input pointer
    ATLASSERT( hashValue!= NULL );

    // Table with hex digits for integers 0,1,2,...15
    static const TCHAR * digits = TEXT("0123456789abcdef");

    // 16 bytes in MD5 digest
    static const int md5Len = 16;

    // Array of TCHAR's storing the MD5 digest string in hex
    // (each MD5 byte is represented with two hex digits, and +1 is for end-of-string)
    TCHAR hexDigest[ (md5Len * 2) + 1 ];

    TCHAR * pCurrHexDigit = hexDigest;
    const BYTE * pCurrDigestByte = hashValue;
    for ( int i = 0; i < md5Len; i++ )
    {
        *pCurrHexDigit++ = digits[ (*pCurrDigestByte) >> 4 ];      // high nibble of current byte
        *pCurrHexDigit++ = digits[ (*pCurrDigestByte) & 0x0F ];    // low nibble of current byte

        // Process next digest byte
        ++pCurrDigestByte;
    }

    // End of string
    *pCurrHexDigit = TEXT('\0');



    // The above code is equivalent to the following code
    // (but it's faster!)
    //
    //    CString strDigest;
    //    CString strHexByte;
    //    for ( int i = 0; i < cbMD5Len; i++ )
    //    {
    //        strHexByte.Format( TEXT("%02X"), pMD5Digest[i] );
    //        strDigest += strHexByte;
    //    }
    //


    // Return a CString instance
    return hexDigest;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -