有沒有大佬知道為什么這個md5演算法,對32個位元組以下的資料加密就不會出錯,給32以及32個位元組以上的資料加密結果就和網上的md5在線加密工具不一樣?
代碼:
void MD5::MD5Encode
(
_In_ const char* text,
_In_ size_t len,
_In_ char* dst
)
{
//分組
short output[16];
char dest[16];
//SHORT_MD5_LEN等于16表示output的長度
//CHAR_MD5_LEN=34,表示在存放輸出字串長度+2
memset(dest, 0, SHORT_MD5_LEN);
memset(dst, 0, CHAR_MD5_LEN);
//四組幻數
unsigned int h[] = { 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476 };
static const unsigned int k[64] =
{
0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee,
0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa,
0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed,
0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,
0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05,
0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039,
0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391
};
//四輪回圈(GG,FF,HH,II)每輪回圈每一步所要位移的位數
static const unsigned int qz[] =
{
7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22,
5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20,
4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23,
6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21
};
static const unsigned int s[] =
{
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
1, 6, 11, 0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12,
5, 8, 11, 14, 1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15, 2,
0, 7, 14, 5, 12, 3, 10, 1, 8, 15, 6, 13, 4, 11, 2, 9
};
unsigned int H[4], i, j, f, tmp, R;
//N*512+448
//N=(資料長度+64(bit))/512(bit),
//任意資料長度+64bit剛好是512倍數
size_t n_len = (len / 64) * 64 + 56;
unsigned char *n_text = (unsigned char *)malloc(n_len + 8);
memset(n_text, 0, n_len + 8);
memcpy(n_text, text, len);
//末尾添加二進制1000 0000
n_text[len] = 0x80;
n_text[n_len] = (unsigned int)len << 3;
//每64位元組(512位)
//處理一次,因為填充過后的數剛好是64的倍數
for (j = 0; j < n_len; j += 64)
{
memcpy(H, h, 4 * sizeof(unsigned int));
//一共回圈64次,分為四組
for (i = 0; i < 64; i++)
{
//四組非線性函式運算,用這個開關陳述句來判斷是第幾組
//0~16第一組,16~32第二組
//32~48第三組,48~64第四組
int ui = i / 16;
switch (ui)
{
//H[1]=X,H[2]=Y,H[3]=Z
//F(X,Y,Z)
case 0: f = (H[1] & H[2]) | ((~H[1]) & H[3]); break;
//G(X,Y,Z)
case 1: f = (H[3] & H[1]) | (H[2] & (~H[3])); break;
//H(X,Y,Z)
case 2: f = H[1] ^ H[2] ^ H[3]; break;
//I
case 3: f = H[2] ^ (H[1] | (~H[3])); break;
}
//abcd分別交換位置
tmp = H[3];
H[3] = H[2];
H[2] = H[1];
//R=(a+?(bcd)+M?+ti)
R = H[0] + f + k[i] + ((unsigned int *)n_text)[s[i] + j];
//b+((a+?(bcd)+M?+ti)<<s))
H[1] = H[1] + ((R << qz[i]) | (R >> (32 - qz[i])));
H[0] = tmp;
}
//每輪回圈結束后,ABCD分別與abcd相加
for (i = 0; i < 4; i++) h[i] += H[i];
}
free(n_text);
memcpy(dest, h, 16);
//與0xff位與將高位的ff變為00
for (int i = 0; i < 16; i++)
output[i] = dest[i] & 0xff;
//將十六進制資料列印成字串
for (int i = 0; i < SHORT_MD5_LEN; i++)
sprintf_s(dst + i * 2, 3, "%02x", output[i]);
}
親自用字串一個一個試過一旦字串長度超過32個位元組結果就和網上在線工具的結果不一樣
小于32:


大于32


uj5u.com熱心網友回復:
太難了。。。uj5u.com熱心網友回復:
資料長度填充, 有8個位元組, 你只填充了1個位元組.當長度超過32位元組(也就是256bits)原始長度就不對了.
n_text[n_len] = (unsigned int)len << 3;
改成
*(unsigned long long*)(n_text+n_len) = (unsigned long long)len << 3;
這樣, 這段代碼可以正確計算小于 56 位元組的MD5,
超過還是有問題.
uj5u.com熱心網友回復:
你的長度計算公式錯了,size_t n_len = (len / 64) * 64 + 56;
當 len = 58, 這個會算出 n_len=56, 反而比len小.
uj5u.com熱心網友回復:
那對于超過56位元組的資料有啥辦法嗎
uj5u.com熱心網友回復:
那對于超過56位元組的資料有什么辦法嗎
uj5u.com熱心網友回復:
超過56位元組, 就要分;兩個組了.說明代碼在處理分組的地方有問題.
uj5u.com熱心網友回復:
是不是超過56個位元組的資料單獨再變成一個128位的資料,然后就把一個超過56個位元組的資料變成了兩個128位的加密字串?
uj5u.com熱心網友回復:
#include <iostream>
#define SHORT_MD5_LEN 16
#define CHAR_MD5_LEN 34
void MD5Encode(_In_ const char *text, _In_ size_t len, _In_ char *dst) {
//分組
short output[16];
char dest[16];
// SHORT_MD5_LEN等于16表示output的長度
// CHAR_MD5_LEN=34,表示在存放輸出字串長度+2
memset(dest, 0, SHORT_MD5_LEN);
memset(dst, 0, CHAR_MD5_LEN);
//四組幻數
unsigned int H[] = {0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476};
static const unsigned int k[64] = {
0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 0xf57c0faf, 0x4787c62a,
0xa8304613, 0xfd469501, 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, 0xf61e2562, 0xc040b340,
0x265e5a51, 0xe9b6c7aa, 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, 0xa9e3e905, 0xfcefa3f8,
0x676f02d9, 0x8d2a4c8a, 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,
0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, 0x289b7ec6, 0xeaa127fa,
0xd4ef3085, 0x04881d05, 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, 0x655b59c3, 0x8f0ccc92,
0xffeff47d, 0x85845dd1, 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391};
//四輪回圈(GG,FF,HH,II)每輪回圈每一步所要位移的位數
static const unsigned int qz[] = {
7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22,
5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20,
4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23,
6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21};
static const unsigned int s[] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
1, 6, 11, 0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12,
5, 8, 11, 14, 1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15, 2,
0, 7, 14, 5, 12, 3, 10, 1, 8, 15, 6, 13, 4, 11, 2, 9};
unsigned int h[4], i, j, f, tmp, R;
// N*512+448
// N=(資料長度+64(bit))/512(bit),
//任意資料長度+64bit剛好是512倍數
size_t n_len = ((len + 8) / 64) * 64 + 56;
unsigned char *n_text = (unsigned char *)malloc(n_len + 8);
memset(n_text, 0, n_len + 8);
memcpy(n_text, text, len);
//末尾添加二進制1000 0000
n_text[len] = 0x80;
*(unsigned long *)(n_text+n_len) = (unsigned long )len << 3;
//每64位元組(512位)
//處理一次,因為填充過后的數剛好是64的倍數
for (j = 0; j < n_len+8; j += 64) {
//memcpy(H, h, 4 * sizeof(unsigned int));
memcpy(h, H, 4 * sizeof(unsigned int));
//一共回圈64次,分為四組
for (i = 0; i < 64; i++) {
//四組非線性函式運算,用這個開關陳述句來判斷是第幾組
// 0~16第一組,16~32第二組
// 32~48第三組,48~64第四組
int ui = i / 16;
switch (ui) {
// H[1]=X,H[2]=Y,H[3]=Z
// F(X,Y,Z)
case 0:
f = (H[1] & H[2]) | ((~H[1]) & H[3]);
break;
// G(X,Y,Z)
case 1:
f = (H[3] & H[1]) | (H[2] & (~H[3]));
break;
// H(X,Y,Z)
case 2:
f = H[1] ^ H[2] ^ H[3];
break;
// I
case 3:
f = H[2] ^ (H[1] | (~H[3]));
break;
}
// abcd分別交換位置
tmp = H[3];
H[3] = H[2];
H[2] = H[1];
// R=(a+?(bcd)+M?+ti)
R = H[0] + f + k[i] + ((unsigned int *)n_text)[s[i] + j/4]; // !!!! j是位元組, int 是4位元組
// b+((a+?(bcd)+M?+ti)<<s))
H[1] = H[1] + ((R << qz[i]) | (R >> (32 - qz[i])));
H[0] = tmp;
}
//每輪回圈結束后,ABCD分別與abcd相加
for (i = 0; i < 4; i++) h[i] += H[i];
for (i = 0; i < 4; i++) H[i] = h[i];
}
free(n_text);
memcpy(dest, h, 16);
//與0xff位與將高位的ff變為00
for (int i = 0; i < 16; i++) output[i] = dest[i] & 0xff;
//將十六進制資料列印成字串
for (int i = 0; i < SHORT_MD5_LEN; i++)
sprintf_s(dst + i * 2, 3, "%02x", output[i]);
}
int main() {
char a[] = "qqqq"; // 3BAD6AF0FA4B8B330D162E19938EE981
char b[] = "qqqqwwwqqqqwwwqeqqqqwwwqqqqwwwqe"; // 284779365D7E17760476E8597C2F4796
char c[] = "qqqqwwwqqqqwwwqeqqqqwwwqqqqwwwq"; // F45FEDAADCBA7E5B60AE6D8A06682049
char d[] = "qqqqwwwqqqqwwwqeqqqqwwwqqqqwwwqqqqqwwwqqqqwwwqeqqqqwwwq"; // 668B5A6DBFF600B2F9D24D83EA13AA2A
char e[] = "qqqqwwwqqqqwwwqeqqqqwwwqqqqwwwqqqqqwwwqqqqwwwqeqqqqwwwqq"; // 3770DB2BB5D5AEE24E0A71D3BBFA6B3E X
char f[] = "qqqqwwwqqqqwwwqeqqqqwwwqqqqwwwqqqqqwwwqqqqwwwqeqqqqwwwqqqqqqwwwqqqqwwwqeqqqqwwwqqqqwwwqqqqqwwwqqqqwwwqeqqqqwwwqq"; // C3189726A2965E7E4525D2507134655C
char x[128];
MD5Encode(a, sizeof(a)-1, x);
MD5Encode(b, sizeof(b)-1, x);
MD5Encode(c, sizeof(c)-1, x);
MD5Encode(d, sizeof(d)-1, x);
MD5Encode(e, sizeof(e)-1, x);
MD5Encode(f, sizeof(f)-1, x);
return 0;
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/66128.html
標籤:C++ 語言
上一篇:歡迎指教
下一篇:求助大佬 萬分感謝
