• [Windows编程笔记]HASH值的计算


    《Windows黑客编程技术详解》学习笔记

    HASH就是把任意长度的输入通过HASH算法变换成固定长度的输出,该输出就是HASH值。

    函数介绍

    // 用于获取特定加密服务提供程序(CSP)内特定密钥容器的句柄,返回的句柄使用选定CSP的CryptoAPI函数。
    BOOL CryptAcquireContextA(
      HCRYPTPROV *phProv,  // 指向CSP句柄的指针。当完成CSP时,通过调用CryptReleaseContext函数释放句柄。
      LPCSTR     szContainer,  // NULL
      LPCSTR     szProvider,  // NULL
      DWORD      dwProvType,  // PROV_RSA_AES表示支持RSA、AES、HASH算法
      DWORD      dwFlags  // CRYPT_VERIFYCONTEXT表示程序不需要使用公钥/私钥对,例如只执行HASH和对称加密
    );
    ​
    BOOL CryptCreateHash(
      HCRYPTPROV hProv,  // CryptAcquireContextA创建的CSP句柄
      ALG_ID     Algid,  // 要使用的HASH算法,由用户传入
      HCRYPTKEY  hKey,  // NULL
      DWORD      dwFlags,  // NULL
      HCRYPTHASH *phHash  // 新哈希对象的地址
    );
    ​
    BOOL CryptHashData(
      HCRYPTHASH hHash,  // CryptCreateHash创建的哈希对象的句柄
      const BYTE *pbData,  // 指向要计算HASH的数据的指针
      DWORD      dwDataLen,  // 要计算的数据的字节数
      DWORD      dwFlags  // 0
    );
    ​
    BOOL CryptGetHashParam(
      HCRYPTHASH hHash,  // CryptCreateHash创建的哈希对象的句柄
      DWORD      dwParam,  // 查询类型。可以选择查询HASH结果的大小或HASH值
      BYTE       *pbData,  // 指向接收数据的缓冲区的指针
      DWORD      *pdwDataLen,  // pbData的字节数
      DWORD      dwFlags  // 0
    );

    编码实现

    代码来自https://www.jb51.net/books/755116.html

    // CryptoApi_Hash_Test.cpp : 定义控制台应用程序的入口点。
    //
    ​
    #include <stdio.h>
    #include <Windows.h>
    #include <tchar.h>
    ​
    ​
    void ShowError(char *pszText)
    {
        char szErr[MAX_PATH] = { 0 };
        ::wsprintf(szErr, "%s Error[%d]
    ", pszText, ::GetLastError());
    #ifdef _DEBUG
        ::MessageBox(NULL, szErr, "ERROR", MB_OK | MB_ICONERROR);
    #endif
    }
    ​
    ​
    BOOL GetFileData(char *pszFilePath, BYTE **ppFileData, DWORD *pdwFileDataLength)
    {
        BOOL bRet = TRUE;
        BYTE *pFileData = NULL;
        DWORD dwFileDataLength = 0;
        HANDLE hFile = NULL;
        DWORD dwTemp = 0;
    ​
        do
        {
            hFile = ::CreateFile(pszFilePath, GENERIC_READ | GENERIC_WRITE,
                FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
                FILE_ATTRIBUTE_ARCHIVE, NULL);
            if (INVALID_HANDLE_VALUE == hFile)
            {
                bRet = FALSE;
                ShowError("CreateFile");
                break;
            }
    ​
            dwFileDataLength = ::GetFileSize(hFile, NULL);
    ​
            pFileData = new BYTE[dwFileDataLength];
            if (NULL == pFileData)
            {
                bRet = FALSE;
                ShowError("new");
                break;
            }
            ::RtlZeroMemory(pFileData, dwFileDataLength);
    ​
            ::ReadFile(hFile, pFileData, dwFileDataLength, &dwTemp, NULL);
    ​
            // 返回
            *ppFileData = pFileData;
            *pdwFileDataLength = dwFileDataLength;
    ​
        } while (FALSE);
    ​
        if (hFile)
        {
            ::CloseHandle(hFile);
        }
    ​
        return bRet;
    }
    ​
    ​
    BOOL CalculateHash(BYTE *pData, DWORD dwDataLength, ALG_ID algHashType, BYTE **ppHashData, DWORD *pdwHashDataLength)
    {
        HCRYPTPROV hCryptProv = NULL;
        HCRYPTHASH hCryptHash = NULL;
        BYTE *pHashData = NULL;
        DWORD dwHashDataLength = 0;
        DWORD dwTemp = 0;
        BOOL bRet = FALSE;
    ​
    ​
        do
        {
            // 获得指定CSP的密钥容器的句柄
            bRet = ::CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_AES, CRYPT_VERIFYCONTEXT);
            if (FALSE == bRet)
            {
                ShowError("CryptAcquireContext");
                break;
            }
    ​
            // 创建一个HASH对象, 指定HASH算法
            bRet = ::CryptCreateHash(hCryptProv, algHashType, NULL, NULL, &hCryptHash);
            if (FALSE == bRet)
            {
                ShowError("CryptCreateHash");
                break;
            }
    ​
            // 计算HASH数据
            bRet = ::CryptHashData(hCryptHash, pData, dwDataLength, 0);
            if (FALSE == bRet)
            {
                ShowError("CryptHashData");
                break;
            }
    ​
            // 获取HASH结果的大小
            dwTemp = sizeof(dwHashDataLength);
            bRet = ::CryptGetHashParam(hCryptHash, HP_HASHSIZE, (BYTE *)(&dwHashDataLength), &dwTemp, 0);
            if (FALSE == bRet)
            {
                ShowError("CryptGetHashParam");
    break;
        }
    ​
    // 申请内存
    pHashData = new BYTE[dwHashDataLength];
    if (NULL == pHashData)
        {
    bRet = FALSE;
    ShowError("new");
    break;
        }
        ::RtlZeroMemory(pHashData, dwHashDataLength);
    ​
    // 获取HASH结果数据
    bRet = ::CryptGetHashParam(hCryptHash, HP_HASHVAL, pHashData, &dwHashDataLength, 0);
    if (FALSE == bRet)
        {
    ShowError("CryptGetHashParam");
    break;
        }
    ​
    // 返回数据
    *ppHashData = pHashData;
    *pdwHashDataLength = dwHashDataLength;
    ​
        } while (FALSE);
    ​
    // 释放关闭
    if (FALSE == bRet)
        {
    if (pHashData)
        {
    delete[]pHashData;
    pHashData = NULL;
        }
        }
    if (hCryptHash)
        {
        ::CryptDestroyHash(hCryptHash);
        }
    if (hCryptProv)
        {
        ::CryptReleaseContext(hCryptProv, 0);
        }
    ​
    return bRet;
    }
    ​
    ​
    int _tmain(int argc, _TCHAR* argv[])
    {
    BYTE *pData = NULL;
    DWORD dwDataLength = 0;
    DWORD i = 0;
    BYTE *pHashData = NULL;
    DWORD dwHashDataLength = 0;
    ​
    // 读取文件数据
    GetFileData("C:\Users\Administrator\Desktop\Project8.exe", &pData, &dwDataLength);
    ​
    // MD5
    CalculateHash(pData, dwDataLength, CALG_MD5, &pHashData, &dwHashDataLength);
    printf("MD5[%d]
    ", dwHashDataLength);
    for (i = 0; i < dwHashDataLength; i++)
        {
    printf("%x", pHashData[i]);
        }
    printf("
    
    ", dwHashDataLength);
    if (pHashData)
        {
    delete[]pHashData;
    pHashData = NULL;
        }
    ​
    // SHA1
    CalculateHash(pData, dwDataLength, CALG_SHA1, &pHashData, &dwHashDataLength);
    printf("SHA1[%d]
    ", dwHashDataLength);
    for (i = 0; i < dwHashDataLength; i++)
        {
    printf("%x", pHashData[i]);
        }
    printf("
    
    ", dwHashDataLength);
    if (pHashData)
        {
    delete[]pHashData;
    pHashData = NULL;
        }
    ​
    // SHA256
    CalculateHash(pData, dwDataLength, CALG_SHA_256, &pHashData, &dwHashDataLength);
    printf("SHA256[%d]
    ", dwHashDataLength);
    for (i = 0; i < dwHashDataLength; i++)
        {
    printf("%x", pHashData[i]);
        }
    printf("
    
    ", dwHashDataLength);
    if (pHashData)
        {
    delete[]pHashData;
    pHashData = NULL;
        }
    ​
    system("pause");
    return 0;
    }

    实现过程

    首先写一个GetFileData函数来获取文件数据,其中用了CreateFile函数来打开文件

    HANDLE CreateFileA(
      LPCSTR                lpFileName,  // 文件路径和文件名
      DWORD                 dwDesiredAccess,  // GENERIC_READ | GENERIC_WRITE表示读写权限
      DWORD                 dwShareMode,  // FILE_SHARE_READ | FILE_SHARE_WRITE表示共享读写权限
      LPSECURITY_ATTRIBUTES lpSecurityAttributes,  // NULL
      DWORD                 dwCreationDisposition,  // OPEN_EXISTING表示仅当文件存在时打开文件
      DWORD                 dwFlagsAndAttributes,  // FILE_ATTRIBUTE_ARCHIVE表示标记要备份或删除的文件
      HANDLE                hTemplateFile  // NULL
    );

    然后用GetFileSize函数来获取文件长度

    DWORD GetFileSize(
      HANDLE  hFile,  // 文件的句柄
      LPDWORD lpFileSizeHigh  // NULL
    );

    然后用ReadFile函数将文件内容读取到新的内存空间

    BOOL ReadFile(
      HANDLE       hFile,  // 文件句柄
      LPVOID       lpBuffer,  // 指向接收文件内容的缓冲区的指针
      DWORD        nNumberOfBytesToRead,  // 读取的最大字节数
      LPDWORD      lpNumberOfBytesRead,  // 接收读取的字节数
      LPOVERLAPPED lpOverlapped  // NULL
    );

    GetFileData函数返回了文件内容和文件内容长度。

    接着写了CalculateHash函数来计算HASH值,整体上就是上面的4个API函数依次用。首先用CryptAcquireContextA函数获取一个指向CSP句柄的指针,然后用CryptCreateHash函数在CSP中创建一个空的HASH对象并获取对象句柄,并可以指定HASH算法,接着使用CryptHashData函数来计算数据的HASH值,结果存放在HASH对象中,最后使用CryptGetHashParam函数来获取想要的数据,可以获取的数据有三种:HASH算法、HASH值长度、HASH值。获取完HASH值后使用CryptReleaseContext函数释放CSP句柄,使用CryptDestroyHash函数来释放HASH对象句柄。

    小结

    计算HASH值的操作步骤主要是创建空HASH对象,然后将数据添加到HASH对象中并计算HASH值。因为有不同的HASH算法,HASH值长度也不同,所以在调用CryptGetHashParam函数获取HASH值之前,应先获取HASH值的大小,以便申请足够的缓冲区。

     

  • 相关阅读:
    J2EE学习笔记:Filter
    J2EE学习笔记:HTTP协议
    J2EE学习笔记:JSP
    Hibernate 笔记(二) 数据关系
    top命令总结
    让gdb能打印C++中的容器类型
    ps命令注意事项
    自己动手写一个自动登录脚本gg
    request 中url拼接排序参数与签名算法
    python3.7 AES.MODE_ECB(128位) pkcs5padding 加密算法
  • 原文地址:https://www.cnblogs.com/rnss/p/15328653.html
Copyright © 2020-2023  润新知