通过 c++ WinAPI 计算 MD5 哈希值
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/13256446/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Compute MD5 hash value by c++ WinAPI
提问by RRR
My C++ app needs to compute an MD5 hash value. Currently, it is done by OpenSSL, and I want to use WinAPI - to avoid dependencies on external libraries.
我的 C++ 应用程序需要计算 MD5 哈希值。目前,它是由 OpenSSL 完成的,我想使用 WinAPI - 以避免对外部库的依赖。
I wrote this code:
我写了这段代码:
HCRYPTPROV hCryptProv = NULL;
HCRYPTHASH hHash = NULL;
HCRYPTHASH hHexHash = NULL;
HASH HA1;
HASHHEX HA1HEX;
DWORD data = HASHLEN;
// Get a handle to a cryptography provider context.
if(!CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, 0))
{
goto err;
}
// Acquire a hash object handle.
if(!CryptCreateHash(hCryptProv, CALG_MD5, 0, 0, &hHash))
{
goto err;
}
CryptHashData(hHash, (const BYTE *)str, strlen(str), 0);
now, the strange thing is that sometimes it works well, but in other times the CryptAcquireContext returns NTE_BAD_KEYSET error, that according to MSDN :
现在,奇怪的是有时它运行良好,但在其他时候 CryptAcquireContext 返回 NTE_BAD_KEYSET 错误,根据 MSDN :
The key container could not be opened. A common cause of this error is that the key container does not exist. To create a key container, call CryptAcquireContext using the CRYPT_NEWKEYSET flag. This error code can also indicate that access to an existing key container is denied. Access rights to the container can be granted by the key set creator by using CryptSetProvParam.
Blockquote
无法打开密钥容器。此错误的常见原因是密钥容器不存在。要创建密钥容器,请使用 CRYPT_NEWKEYSET 标志调用 CryptAcquireContext。此错误代码还可能表明对现有密钥容器的访问被拒绝。密钥集创建者可以使用 CryptSetProvParam 授予对容器的访问权限。
块引用
Now my questions are:
现在我的问题是:
- If I call CryptSetProvParam, what exactly does it do? Is it normal that simple application changes the OS settings?
- Is there any less difficult way to compute MD5 in C++ windows?
- 如果我调用 CryptSetProvParam,它到底做了什么?简单的应用程序更改操作系统设置是否正常?
- 在 C++ 窗口中计算 MD5 有什么不那么困难的方法吗?
I'll appreciate if someone gives me good advice on what to do.
Thanks.
如果有人就该做什么向我提出好的建议,我将不胜感激。
谢谢。
回答by Patrick M
So, I found an example that does what you want at http://msdn.microsoft.com/en-us/library/aa382380%28VS.85%29.aspx
因此,我在http://msdn.microsoft.com/en-us/library/aa382380%28VS.85%29.aspx找到了一个可以满足您要求的示例
Looking at their code, the difference I see is this line:
查看他们的代码,我看到的不同之处在于这一行:
Theirs: CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)
他们的: CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)
Yours: CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, 0)
你的:CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, 0)
So, reading up on that flag, I find this information:
因此,阅读该标志后,我找到了以下信息:
CRYPT_VERIFYCONTEXT: This option is intended for applications that are using ephemeral keys, or applications that do not require access to persisted private keys, such as applications that perform only hashing, encryption, and digital signature verification. Only applications that create signatures or decrypt messages need access to a private key. In most cases, this flag should be set.
CRYPT_VERIFYCONTEXT:此选项适用于使用临时密钥的应用程序,或不需要访问持久私钥的应用程序,例如仅执行散列、加密和数字签名验证的应用程序。只有创建签名或解密消息的应用程序需要访问私钥。在大多数情况下,应设置此标志。
http://msdn.microsoft.com/en-us/library/windows/desktop/aa379886%28v=vs.85%29.aspx
http://msdn.microsoft.com/en-us/library/windows/desktop/aa379886%28v=vs.85%29.aspx
So, it looks like you are trying to get access to information you don't need, and the request is denied. So the best option is to tell Windows you don't need that information by including that flag.
因此,您似乎试图访问不需要的信息,但请求被拒绝。因此,最好的选择是通过包含该标志来告诉 Windows 您不需要该信息。
回答by Naszta
I like to use PROV_RSA_AES
and CRYPT_VERIFYCONTEXT
, because the most of the hashes are supported.
我喜欢使用PROV_RSA_AES
and CRYPT_VERIFYCONTEXT
,因为支持大多数散列。
Here is a working example:
这是一个工作示例:
#include <Wincrypt.h>
enum HashType
{
HashSha1, HashMd5, HashSha256
};
std::string GetHashText( const void * data, const size_t data_size, HashType hashType )
{
HCRYPTPROV hProv = NULL;
if ( ! CryptAcquireContext( &hProv, NULL, NULL, PROV_RSA_AES, CRYPT_VERIFYCONTEXT ) ) {
return "";
}
BOOL hash_ok = FALSE;
HCRYPTPROV hHash = NULL;
switch ( hashType ) {
case HashSha1 : hash_ok = CryptCreateHash( hProv, CALG_SHA1, 0, 0, &hHash ); break;
case HashMd5 : hash_ok = CryptCreateHash( hProv, CALG_MD5, 0, 0, &hHash ); break;
case HashSha256 : hash_ok = CryptCreateHash( hProv, CALG_SHA_256, 0, 0, &hHash ); break;
}
if ( ! hash_ok ) {
CryptReleaseContext(hProv, 0);
return "";
}
if ( ! CryptHashData( hHash, static_cast<const BYTE *>(data), data_size, 0 ) ) {
CryptDestroyHash(hHash);
CryptReleaseContext(hProv, 0);
return "";
}
DWORD cbHashSize = 0, dwCount = sizeof(DWORD);
if( ! CryptGetHashParam( hHash, HP_HASHSIZE, (BYTE *)&cbHashSize, &dwCount, 0 ) ) {
CryptDestroyHash(hHash);
CryptReleaseContext(hProv, 0);
return "";
}
std::vector<BYTE> buffer( cbHashSize );
if ( ! CryptGetHashParam( hHash, HP_HASHVAL, reinterpret_cast<BYTE*>( &buffer[0] ), &cbHashSize, 0) ) {
CryptDestroyHash(hHash);
CryptReleaseContext(hProv, 0);
return "";
}
std::ostringstream oss;
for ( std::vector<BYTE>::const_iterator iter = buffer.begin(); iter != buffer.end(); ++iter ) {
oss.fill('0');
oss.width(2);
oss << std::hex << static_cast<const int>(*iter);
}
CryptDestroyHash(hHash);
CryptReleaseContext(hProv, 0);
return oss.str();
}
回答by Sanya Tayal
The following 'MD5.h' file can be created and a simple code could be used.
可以创建以下“MD5.h”文件,并可以使用简单的代码。
main.cpp
主程序
#include "md5.h"
int main()
{
MD5 md5;
puts( md5.digestString( "HELLO THERE I AM MD5!" ) ) ;
// print the digest for a binary file on disk.
puts( md5.digestFile( "C:\WINDOWS\notepad.exe" ) ) ;
return 0;
}
MD5.h
MD5.h
#ifndef MD5_H
#define MD5_H
#include <stdio.h>
#include <string.h>
#pragma region MD5 defines
// Constants for MD5Transform routine.
#define S11 7
#define S12 12
#define S13 17
#define S14 22
#define S21 5
#define S22 9
#define S23 14
#define S24 20
#define S31 4
#define S32 11
#define S33 16
#define S34 23
#define S41 6
#define S42 10
#define S43 15
#define S44 21
static unsigned char PADDING[64] = {
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
// F, G, H and I are basic MD5 functions.
#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
#define H(x, y, z) ((x) ^ (y) ^ (z))
#define I(x, y, z) ((y) ^ ((x) | (~z)))
// ROTATE_LEFT rotates x left n bits.
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
// FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
// Rotation is separate from addition to prevent recomputation.
#define FF(a, b, c, d, x, s, ac) { \
(a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
#define GG(a, b, c, d, x, s, ac) { \
(a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
#define HH(a, b, c, d, x, s, ac) { \
(a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
#define II(a, b, c, d, x, s, ac) { \
(a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
#pragma endregion
typedef unsigned char BYTE;
// POINTER defines a generic pointer type
typedef unsigned char *POINTER;
// UINT2 defines a two byte word
typedef unsigned short int UINT2;
// UINT4 defines a four byte word
typedef unsigned long int UINT4;
// convenient object that wraps
// the C-functions for use in C++ only
class MD5
{
private:
struct __context_t {
UINT4 state[4]; /* state (ABCD) */
UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */
unsigned char buffer[64]; /* input buffer */
} context;
#pragma region static helper functions
// The core of the MD5 algorithm is here.
// MD5 basic transformation. Transforms state based on block.
static void MD5Transform(UINT4 state[4], unsigned char block[64])
{
UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
Decode(x, block, 64);
/* Round 1 */
FF(a, b, c, d, x[0], S11, 0xd76aa478); /* 1 */
FF(d, a, b, c, x[1], S12, 0xe8c7b756); /* 2 */
FF(c, d, a, b, x[2], S13, 0x242070db); /* 3 */
FF(b, c, d, a, x[3], S14, 0xc1bdceee); /* 4 */
FF(a, b, c, d, x[4], S11, 0xf57c0faf); /* 5 */
FF(d, a, b, c, x[5], S12, 0x4787c62a); /* 6 */
FF(c, d, a, b, x[6], S13, 0xa8304613); /* 7 */
FF(b, c, d, a, x[7], S14, 0xfd469501); /* 8 */
FF(a, b, c, d, x[8], S11, 0x698098d8); /* 9 */
FF(d, a, b, c, x[9], S12, 0x8b44f7af); /* 10 */
FF(c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
FF(b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
FF(a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
FF(d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
FF(c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
FF(b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
/* Round 2 */
GG(a, b, c, d, x[1], S21, 0xf61e2562); /* 17 */
GG(d, a, b, c, x[6], S22, 0xc040b340); /* 18 */
GG(c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
GG(b, c, d, a, x[0], S24, 0xe9b6c7aa); /* 20 */
GG(a, b, c, d, x[5], S21, 0xd62f105d); /* 21 */
GG(d, a, b, c, x[10], S22, 0x2441453); /* 22 */
GG(c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
GG(b, c, d, a, x[4], S24, 0xe7d3fbc8); /* 24 */
GG(a, b, c, d, x[9], S21, 0x21e1cde6); /* 25 */
GG(d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
GG(c, d, a, b, x[3], S23, 0xf4d50d87); /* 27 */
GG(b, c, d, a, x[8], S24, 0x455a14ed); /* 28 */
GG(a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
GG(d, a, b, c, x[2], S22, 0xfcefa3f8); /* 30 */
GG(c, d, a, b, x[7], S23, 0x676f02d9); /* 31 */
GG(b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
/* Round 3 */
HH(a, b, c, d, x[5], S31, 0xfffa3942); /* 33 */
HH(d, a, b, c, x[8], S32, 0x8771f681); /* 34 */
HH(c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
HH(b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
HH(a, b, c, d, x[1], S31, 0xa4beea44); /* 37 */
HH(d, a, b, c, x[4], S32, 0x4bdecfa9); /* 38 */
HH(c, d, a, b, x[7], S33, 0xf6bb4b60); /* 39 */
HH(b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
HH(a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
HH(d, a, b, c, x[0], S32, 0xeaa127fa); /* 42 */
HH(c, d, a, b, x[3], S33, 0xd4ef3085); /* 43 */
HH(b, c, d, a, x[6], S34, 0x4881d05); /* 44 */
HH(a, b, c, d, x[9], S31, 0xd9d4d039); /* 45 */
HH(d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
HH(c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
HH(b, c, d, a, x[2], S34, 0xc4ac5665); /* 48 */
/* Round 4 */
II(a, b, c, d, x[0], S41, 0xf4292244); /* 49 */
II(d, a, b, c, x[7], S42, 0x432aff97); /* 50 */
II(c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
II(b, c, d, a, x[5], S44, 0xfc93a039); /* 52 */
II(a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
II(d, a, b, c, x[3], S42, 0x8f0ccc92); /* 54 */
II(c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
II(b, c, d, a, x[1], S44, 0x85845dd1); /* 56 */
II(a, b, c, d, x[8], S41, 0x6fa87e4f); /* 57 */
II(d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
II(c, d, a, b, x[6], S43, 0xa3014314); /* 59 */
II(b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
II(a, b, c, d, x[4], S41, 0xf7537e82); /* 61 */
II(d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
II(c, d, a, b, x[2], S43, 0x2ad7d2bb); /* 63 */
II(b, c, d, a, x[9], S44, 0xeb86d391); /* 64 */
state[0] += a;
state[1] += b;
state[2] += c;
state[3] += d;
// Zeroize sensitive information.
memset((POINTER)x, 0, sizeof(x));
}
// Encodes input (UINT4) into output (unsigned char). Assumes len is
// a multiple of 4.
static void Encode(unsigned char *output, UINT4 *input, unsigned int len)
{
unsigned int i, j;
for (i = 0, j = 0; j < len; i++, j += 4) {
output[j] = (unsigned char)(input[i] & 0xff);
output[j + 1] = (unsigned char)((input[i] >> 8) & 0xff);
output[j + 2] = (unsigned char)((input[i] >> 16) & 0xff);
output[j + 3] = (unsigned char)((input[i] >> 24) & 0xff);
}
}
// Decodes input (unsigned char) into output (UINT4). Assumes len is
// a multiple of 4.
static void Decode(UINT4 *output, unsigned char *input, unsigned int len)
{
unsigned int i, j;
for (i = 0, j = 0; j < len; i++, j += 4)
output[i] = ((UINT4)input[j]) | (((UINT4)input[j + 1]) << 8) |
(((UINT4)input[j + 2]) << 16) | (((UINT4)input[j + 3]) << 24);
}
#pragma endregion
public:
// MAIN FUNCTIONS
MD5()
{
Init();
}
// MD5 initialization. Begins an MD5 operation, writing a new context.
void Init()
{
context.count[0] = context.count[1] = 0;
// Load magic initialization constants.
context.state[0] = 0x67452301;
context.state[1] = 0xefcdab89;
context.state[2] = 0x98badcfe;
context.state[3] = 0x10325476;
}
// MD5 block update operation. Continues an MD5 message-digest
// operation, processing another message block, and updating the
// context.
void Update(
unsigned char *input, // input block
unsigned int inputLen) // length of input block
{
unsigned int i, index, partLen;
// Compute number of bytes mod 64
index = (unsigned int)((context.count[0] >> 3) & 0x3F);
// Update number of bits
if ((context.count[0] += ((UINT4)inputLen << 3))
< ((UINT4)inputLen << 3))
context.count[1]++;
context.count[1] += ((UINT4)inputLen >> 29);
partLen = 64 - index;
// Transform as many times as possible.
if (inputLen >= partLen) {
memcpy((POINTER)&context.buffer[index], (POINTER)input, partLen);
MD5Transform(context.state, context.buffer);
for (i = partLen; i + 63 < inputLen; i += 64)
MD5Transform(context.state, &input[i]);
index = 0;
}
else
i = 0;
/* Buffer remaining input */
memcpy((POINTER)&context.buffer[index], (POINTER)&input[i], inputLen - i);
}
// MD5 finalization. Ends an MD5 message-digest operation, writing the
// the message digest and zeroizing the context.
// Writes to digestRaw
void Final()
{
unsigned char bits[8];
unsigned int index, padLen;
// Save number of bits
Encode(bits, context.count, 8);
// Pad out to 56 mod 64.
index = (unsigned int)((context.count[0] >> 3) & 0x3f);
padLen = (index < 56) ? (56 - index) : (120 - index);
Update(PADDING, padLen);
// Append length (before padding)
Update(bits, 8);
// Store state in digest
Encode(digestRaw, context.state, 16);
// Zeroize sensitive information.
memset((POINTER)&context, 0, sizeof(context));
writeToString();
}
/// Buffer must be 32+1 (nul) = 33 chars long at least
void writeToString()
{
int pos;
for (pos = 0; pos < 16; pos++)
sprintf(digestChars + (pos * 2), "%02x", digestRaw[pos]);
}
public:
// an MD5 digest is a 16-byte number (32 hex digits)
BYTE digestRaw[16];
// This version of the digest is actually
// a "printf'd" version of the digest.
char digestChars[33];
/// Load a file from disk and digest it
// Digests a file and returns the result.
char* digestFile(char *filename)
{
Init();
FILE *file;
int len;
unsigned char buffer[1024];
if ((file = fopen(filename, "rb")) == NULL)
printf("%s can't be opened\n", filename);
else
{
while (len = fread(buffer, 1, 1024, file))
Update(buffer, len);
Final();
fclose(file);
}
return digestChars;
}
/// Digests a byte-array already in memory
char* digestMemory(BYTE *memchunk, int len)
{
Init();
Update(memchunk, len);
Final();
return digestChars;
}
// Digests a string and prints the result.
char* digestString(char *string)
{
Init();
Update((unsigned char*)string, strlen(string));
Final();
return digestChars;
}
};
#endif
回答by Rudra
I got this link
我有这个链接
but I made some changes in order to run this function on my side, hope it might help
但我做了一些更改以便在我这边运行这个功能,希望它可能会有所帮助
char* HashMD5(char* data, DWORD *result)
{
DWORD dwStatus = 0;
DWORD cbHash = 16;
int i = 0;
HCRYPTPROV cryptProv;
HCRYPTHASH cryptHash;
BYTE hash[16];
char *hex = "0123456789abcdef";
char *strHash;
strHash = (char*)malloc(500);
memset(strHash, '##代码##', 500);
if (!CryptAcquireContext(&cryptProv, NULL, MS_DEF_PROV, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
{
dwStatus = GetLastError();
printf("CryptAcquireContext failed: %d\n", dwStatus);
*result = dwStatus;
return NULL;
}
if (!CryptCreateHash(cryptProv, CALG_MD5, 0, 0, &cryptHash))
{
dwStatus = GetLastError();
printf("CryptCreateHash failed: %d\n", dwStatus);
CryptReleaseContext(cryptProv, 0);
*result = dwStatus;
return NULL;
}
if (!CryptHashData(cryptHash, (BYTE*)data, strlen(data), 0))
{
dwStatus = GetLastError();
printf("CryptHashData failed: %d\n", dwStatus);
CryptReleaseContext(cryptProv, 0);
CryptDestroyHash(cryptHash);
*result = dwStatus;
return NULL;
}
if (!CryptGetHashParam(cryptHash, HP_HASHVAL, hash, &cbHash, 0))
{
dwStatus = GetLastError();
printf("CryptGetHashParam failed: %d\n", dwStatus);
CryptReleaseContext(cryptProv, 0);
CryptDestroyHash(cryptHash);
*result = dwStatus;
return NULL;
}
for (i = 0; i < cbHash; i++)
{
strHash[i * 2] = hex[hash[i] >> 4];
strHash[(i * 2) + 1] = hex[hash[i] & 0xF];
}
CryptReleaseContext(cryptProv, 0);
CryptDestroyHash(cryptHash);
return strHash;
}