具有简单接口的C语言MD5算法实现
1. 关键词
- MD5
- C语言
- 易于使用的
- 示例教程
2. 声明:
本程序修改自文档
The MD5 Message-Digest Algorithm: https://www.ietf.org/rfc/rfc1321.txt
3. 下载
阿里云盘分享: https://www.aliyundrive.com/s/RQ998i2Pg5f
4. 使用
- 通过上面的链接下载源代码(
md5.c
+md5.h
)添加进你的工程项目,或者在网站上复制后粘贴到新建文档中也是个不错的方式。 - 在C++项目中使用需要使用
extern "C" {}
来包含引入的头文件。 - 本程序仅提供了2个主要函数:
MD5File()
: 计算文件的MD5值
MD5Buffer()
:计算内存块的MD5值
和3个外围函数:
MD5Test()
: 测试MD5程序正确性
MD5Print()
:将MD5值打印到屏幕
MD5String()
:将MD5值转换为MD5字符串
*详阅md5.h
,特别注意返回值!
5. 示例
已验证正确运行于Visual Studio 2022 (v143)
#include <stdio.h>
#include <stdlib.h>
extern "C" {
#include "md5.h"
}
int main()
{
/*在客户机上执行一次验证程序,保证计算正确性*/
if (MD5Test()) {
fprintf_s(stderr, "A fatal error occurred in the program.\n");
exit(EXIT_FAILURE);
}
MD5 digest; /*存储数值MD5值的变量*/
MD5_STR mdstr; /*存储MD5字符串的变量*/
/*计算文件的MD5值*/
const char* filename = "md5.c";
if (MD5File(filename, digest)) {
fprintf_s(stderr, "%s can't be opened\n", filename);
exit(EXIT_FAILURE);
}
/*将数值MD5转换成字符串MD5再用printf输出*/
MD5String(digest, mdstr);
printf("%s\n", mdstr);
/*计算上面字符串变量的MD5值并直接输出*/
MD5Buffer(mdstr, sizeof(mdstr), digest);
MD5Print(digest);
return 0;
}
运行结果:
BB2ED9D59B5677A4869D432CD6EDB2B3
E79F34693BD80291E3EB4AB2D5BCC3C1
6. md5.h
#pragma once
/* MD5.H - header file for MD5.C
*/
/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
rights reserved.
License to copy and use this software is granted provided that it
is identified as the "RSA Data Security, Inc. MD5 Message-Digest
Algorithm" in all material mentioning or referencing this software
or this function.
License is also granted to make and use derivative works provided
that such works are identified as "derived from the RSA Data
Security, Inc. MD5 Message-Digest Algorithm" in all material
mentioning or referencing the derived work.
RSA Data Security, Inc. makes no representations concerning either
the merchantability of this software or the suitability of this
software for any particular purpose. It is provided "as is"
without express or implied warranty of any kind.
These notices must be retained in any copies of any part of this
documentation and/or software.
*/
#define MD5_VALUE_LEN 16 //MD5数值的长度
#define MD5_STRING_LEN (32+1) //MD5字符串的长度
typedef unsigned char MD5[MD5_VALUE_LEN]; //MD5的数值类型
typedef char MD5_STR[MD5_STRING_LEN]; //MD5的字符串类型
/* 计算文件的MD5值
* INPUT:
* filename: 要计算的文件
* digest: 用于存储计算结果
* RETURN:
* 0: 正常结束
* -1: 无法打开文件
*/
int MD5File(const char *filename, MD5 digest);
/* 计算内存块的MD5值
* INPUT:
* buffer: 内存块的起始地址
* size: 内存块的长度
* digest: 用于存储计算结果
*/
void MD5Buffer(void *buffer, size_t size, MD5 digest);
/* 测试MD5程序正确性
* RETURN:
* 0: MD5正常运行
* -1: MD5无法正常运行
*/
int MD5Test(void);
/* 将MD5值打印到屏幕
* INPUT:
* digest: 要打印的MD5值
*/
void MD5Print(MD5 digest);
/* 将MD5值转换为MD5字符串
* INPUT:
* digest: 用于转换的MD5值
* str: 用于存放转换结果
*/
void MD5String(MD5 digest, MD5_STR str);
7. md5.c
/* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm
*/
/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
rights reserved.
License to copy and use this software is granted provided that it
is identified as the "RSA Data Security, Inc. MD5 Message-Digest
Algorithm" in all material mentioning or referencing this software
or this function.
License is also granted to make and use derivative works provided
that such works are identified as "derived from the RSA Data
Security, Inc. MD5 Message-Digest Algorithm" in all material
mentioning or referencing the derived work.
RSA Data Security, Inc. makes no representations concerning either
the merchantability of this software or the suitability of this
software for any particular purpose. It is provided "as is"
without express or implied warranty of any kind.
These notices must be retained in any copies of any part of this
documentation and/or software.
*/
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include "md5.h"
typedef uint32_t UINT4;
typedef unsigned char UCHAR;
typedef unsigned int UINT;
/* POINTER defines a generic pointer type */
typedef unsigned char *POINTER;
/* MD5 context. */
typedef struct {
UINT4 state[4]; /* state (ABCD) */
UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */
UCHAR buffer[64]; /* input buffer */
} MD5_CTX;
/* 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 void MD5Init (MD5_CTX *);
static void MD5Update (MD5_CTX *, UCHAR *, UINT);
static void MD5Final (MD5, MD5_CTX *);
static void MD5Transform (UINT4 [4], UCHAR [64]);
static void Encode (UCHAR *, UINT4 *, UINT);
static void Decode (UINT4 *, UCHAR *, UINT);
static void MD5_memcpy (POINTER, POINTER, UINT);
static void MD5_memset (POINTER, int, UINT);
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); \
}
/* MD5 initialization. Begins an MD5 operation, writing a new context.*/
static void MD5Init (context)
MD5_CTX *context; /* context */
{
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.
*/
static void MD5Update (context, input, inputLen)
MD5_CTX *context; /* context */
UCHAR *input; /* input block */
UINT inputLen; /* length of input block */
{
UINT i, index, partLen;
/* Compute number of bytes mod 64 */
index = (UINT)((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) {
MD5_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 */
MD5_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.
*/
static void MD5Final (digest, context)
MD5 digest; /* message digest */
MD5_CTX *context; /* context */
{
UCHAR bits[8];
UINT index, padLen;
/* Save number of bits */
Encode (bits, context->count, 8);
/* Pad out to 56 mod 64.*/
index = (UINT)((context->count[0] >> 3) & 0x3f);
padLen = (index < 56) ? (56 - index) : (120 - index);
MD5Update (context, PADDING, padLen);
/* Append length (before padding) */
MD5Update (context, bits, 8);
/* Store state in digest */
Encode (digest, context->state, 16);
/* Zeroize sensitive information.*/
MD5_memset ((POINTER)context, 0, sizeof (*context));
}
/* MD5 basic transformation. Transforms state based on block.*/
static void MD5Transform (UINT4 state[4], UCHAR 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.*/
MD5_memset((POINTER)x, 0, sizeof(x));
}
/* Encodes input (UINT4) into output (unsigned char). Assumes len is
a multiple of 4.
*/
static void Encode (UCHAR *output, UINT4 *input, UINT len)
{
UINT i, j;
for (i = 0, j = 0; j < len; i++, j += 4) {
output[j] = (UCHAR)(input[i] & 0xff);
output[j+1] = (UCHAR)((input[i] >> 8) & 0xff);
output[j+2] = (UCHAR)((input[i] >> 16) & 0xff);
output[j+3] = (UCHAR)((input[i] >> 24) & 0xff);
}
}
/* Decodes input (unsigned char) into output (UINT4). Assumes len is
a multiple of 4.
*/
static void Decode (UINT4 *output, UCHAR *input, UINT len)
{
UINT 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);
}
/* Note: Replace "for loop" with standard memcpy if possible.*/
static void MD5_memcpy (POINTER output, POINTER input, UINT len)
{
UINT i;
for (i = 0; i < len; i++)
output[i] = input[i];
}
/* Note: Replace "for loop" with standard memset if possible.*/
static void MD5_memset (POINTER output, int value, UINT len)
{
UINT i;
for (i = 0; i < len; i++)
((char *)output)[i] = (char)value;
}
int MD5File (const char *filename, MD5 digest)
{
FILE *file = NULL;
fopen_s(&file, filename, "rb");
if (!file)
return -1;
MD5_CTX context;
MD5Init (&context);
UINT len;
unsigned char buffer[4096];
while ((len = (UINT)fread (buffer, sizeof(UCHAR), 4096u, file)))
MD5Update (&context, buffer, len);
MD5Final (digest, &context);
fclose (file);
return 0;
}
void MD5Buffer(void *buffer, size_t size, MD5 digest)
{
MD5_CTX context;
MD5Init(&context);
const size_t uint_max = UINT32_MAX;
while (size > uint_max) {
MD5Update(&context, (UCHAR*)buffer, UINT32_MAX);
size -= uint_max;
(UCHAR*)buffer += uint_max;
}
MD5Update(&context, (unsigned char*)buffer, (UINT)size);
MD5Final(digest, &context);
}
int MD5Test(void)
{
char* test_str = "hello world!";
char* ans = "FC3FF98E8C6A0D3087D515C0473F8677";
MD5_CTX context;
MD5 digest;
MD5Init(&context);
MD5Update(&context, (unsigned char*)test_str, (UINT)strlen(test_str));
MD5Final(digest, &context);
MD5_STR mdstr;
MD5String(digest, mdstr);
return strncmp(ans, mdstr, MD5_STRING_LEN);
}
/* Prints a message digest in hexadecimal.*/
void MD5Print (MD5 digest)
{
unsigned int i;
for (i = 0; i < 16; i++)
printf ("%02X", digest[i]);
}
void MD5String(MD5 digest, MD5_STR mdstr)
{
unsigned int i, j = 0;
for (i = 0; i < MD5_VALUE_LEN; i++)
j += sprintf_s(mdstr + j, MD5_STRING_LEN - j, "%02X", digest[i]);
}