MD5算法的编程实现_*南有乔木的博客-程序员ITS203_md5实现

技术标签: c++  信息安全  

【实验目的】

1、理解Hash函数的计算原理和特点。
2、理解MD5算法原理。
3、了解MD5值的生成过程。

【实验环境】

windows虚拟机
在目录C:\Program Files\Microsoft Visual Studio\MyProjects\MD5下打开MD5.dsw,在VC6.0环境下编译代码。

【实验预备知识点】

MD5是一种常见的单项散列算法,用以提供消息的完整性保护,计算机界广泛使用的散列算法之一。
算法以512位分组来处理输入的信息,每一分组又被划分为16个32位子分组,经过一系列的处理后,算法的输出由四个32位分组组成,将这四个32位分组级联后产生一个128位的散列值。

【实验内容】

MD5是输入不定长度信息,输出固定长度128bits的演算法。经过程序流程,生产四个32bit数据,最后联合起来为一个128bit散列。

【实验步骤】

MD5算法包括以下五个步骤。
1、 附加填充位
首先填充消息,使其长度为一个比512的倍数小64位的数。填充方法:在消息后面填充一位1,然后填充所需数量的0。填充位的位数从1~512。
2、 附加长度
将原消息长度的64位表示附加在填充后的消息后面。当原消息长度大于2^64时,用消息长度mod 2^64填充。这时,消息长度恰好是512的整数倍。令M[0 1…N−1]为填充后消息的各个字(每字为32位),N是16的倍数。
3、 初始化MD缓冲区
初始化用于计算消息摘要的128位缓冲区。这个缓冲区由四个32位寄存器A、B、C、D表示。寄存器的初始化值为(按低位字节在前的顺序存放):
A: 01234567
B: 89abcdef
C: fedcba98
D: 76543210
4、 按512位的分组处理输入消息
这一步为MD5的主循环,一个压缩函数是本算法的核心。它包括4轮处理。四轮处理具有相似的结构,但每次使用不同的基本逻辑函数,记为F,G,H,I。
F(X,Y,Z)=(X&Y)|((~X)&Z)
G(X,Y,Z)=(X&Z)|(Y&(~Z))
H(X,Y,Z)=XYZ
I(X,Y,Z)=Y^(X|(~Z))
  这四个函数的说明:如果X、Y和Z的对应位是独立和均匀的,那么结果的每一位也应是独立和均匀的。F是一个逐位运算的函数。即,如果X,那么Y,否则Z。函数H是逐位奇偶操作符。
   假设Mj表示消息的第j个子分组(从0到15),
  (x)<<(n)表示把x循环左移n位
   FF(a,b,c,d,Mj,s,ti)表示a=b+((a+(F(b,c,d)+Mj+ti))<<s)
   GG(a,b,c,d,Mj,s,ti)表示a=b+((a+(G(b,c,d)+Mj+ti))<<s)
   HH(a,b,c,d,Mj,s,ti)表示a=b+((a+(H(b,c,d)+Mj+ti))<<s)
   II(a,b,c,d,Mj,s,ti)表示a=b+((a+(I(b,c,d)+Mj+ti))<<s)
  这四轮(64步)是:
第一轮


   FF(a,b,c,d,M0,7,0xd76aa478) 
   FF(d,a,b,c,M1,12,0xe8c7b756)
   FF(c,d,a,b,M2,17,0x242070db)
   FF(b,c,d,a,M3,22,0xc1bdceee)
   FF(a,b,c,d,M4,7,0xf57c0faf)
   FF(d,a,b,c,M5,12,0x4787c62a)
   FF(c,d,a,b,M6,17,0xa8304613)
   FF(b,c,d,a,M7,22,0xfd469501)
   FF(a,b,c,d,M8,7,0x698098d8)
   FF(d,a,b,c,M9,12,0x8b44f7af)
   FF(c,d,a,b,M10,17,0xffff5bb1)
   FF(b,c,d,a,M11,22,0x895cd7be)
   FF(a,b,c,d,M12,7,0x6b901122)
   FF(d,a,b,c,M13,12,0xfd987193)
   FF(c,d,a,b,M14,17,0xa679438e)
   FF(b,c,d,a,M15,22,0x49b40821)
     第二轮
   GG(a,b,c,d,M1,5,0xf61e2562) 
   GG(d,a,b,c,M6,9,0xc040b340)
   GG(c,d,a,b,M11,14,0x265e5a51)
   GG(b,c,d,a,M0,20,0xe9b6c7aa)
   GG(a,b,c,d,M5,5,0xd62f105d)
   GG(d,a,b,c,M10,9,0x02441453)
   GG(c,d,a,b,M15,14,0xd8a1e61)
   GG(b,c,d,a,M4,20,0xe7d3fbc8)
   GG(a,b,c,d,M9,5,0x21e1cde6)
   GG(d,a,b,c,M14,9,0xc33707d6)
   GG(c,d,a,b,M3,14,0xf4d50d87)
   GG(b,c,d,a,M8,20,0x455a14ed)
   GG(a,b,c,d,M13,5,0xa9e3e905)
   GG(d,a,b,c,M2,9,0xfcefa3f8)
   GG(c,d,a,b,M7,14,0x676f02d9)
   GG(b,c,d,a,M12,20,0x8d2a4c8a)
    第三轮
   HH(a,b,c,d,M5,4,0xfffa3942) 
   HH(d,a,b,c,M8,11,0x8771f681)
   HH(c,d,a,b,M11,16,0x6d9d6122)
   HH(b,c,d,a,M14,23,0xfde5380c)
   HH(a,b,c,d,M1,4,0xa4beea44)
   HH(d,a,b,c,M4,11,0x4bdecfa9)
   HH(c,d,a,b,M7,16,0xf6bb4b60)
   HH(b,c,d,a,M10,23,0xbebfbc70)
   HH(a,b,c,d,M13,4,0x289b7ec6)
   HH(d,a,b,c,M0,11,0xeaa127fa)
   HH(c,d,a,b,M3,16,0xd4ef3085)
   HH(b,c,d,a,M6,23,0x04881d05)
   HH(a,b,c,d,M9,4,0xd9d4d039)
   HH(d,a,b,c,M12,11,0xe6db99e5)
   HH(c,d,a,b,M15,16,0x1fa27cf8)
   HH(b,c,d,a,M2,23,0xc4ac5665)
    第四轮
   II(a,b,c,d,M0,6,0xf4292244) 
   II(d,a,b,c,M7,10,0x432aff97)
  II(c,d,a,b,M14,15,0xab9423a7)
   II(b,c,d,a,M5,21,0xfc93a039)
   II(a,b,c,d,M12,6,0x655b59c3)
   II(d,a,b,c,M3,10,0x8f0ccc92)
   II(c,d,a,b,M10,15,0xffeff47d)
   II(b,c,d,a,M1,21,0x85845dd1)
   II(a,b,c,d,M8,6,0x6fa87e4f)
   II(d,a,b,c,M15,10,0xfe2ce6e0)
   II(c,d,a,b,M6,15,0xa3014314)
   II(b,c,d,a,M13,21,0x4e0811a1)
   II(a,b,c,d,M4,6,0xf7537e82)
   II(d,a,b,c,M11,10,0xbd3af235)
   II(c,d,a,b,M2,15,0x2ad7d2bb)
   II(b,c,d,a,M9,21,0xeb86d391)

5、 常数ti的选择
  在第i步中,ti是4294967296*abs(sin(i))的整数部分,i的单位是弧度。(4294967296等于2的32次方)
  所有这些完成之后,将A、B、C、D分别加上a、b、c、d。然后用下一分组数据继续运行算法,最后的输出是A、B、C和D的级联。
6、 以下是程序的关键代码:

//MD5.c 
//MD5.c
#include<stdio.h> 
#include<Windows.h>
void dectobina(int in, int n, int *md5); 
void dectobina_tail(int in, int *md5); 
void hextobina(char *t, int *temp); 
void c_out(int *a); 
void abcd_out(int *a); 
void F(int *b, int *c, int *d, int *temp1, int *temp2); 
void G(int *b, int *c, int *d, int *temp1, int *temp2); 
void H(int *b, int *c, int *d, int *temp); 
void I(int *b, int *c, int *d, int *temp); 
void and(int *a, int *b, int *temp); 
void or(int *a, int *b, int *temp); 
void no(int *a, int *temp); 
void xor(int *a, int *b, int *temp); 
void addto(int *a, int *b, int *temp); 
void dectobina(int in, int n, int *md5) 
{
     
    int j, s, w;   
    s = n / 4 + 1; 
    w = n % 4; 
    j = 1; 
    do 
    {
     
        md5[32 * s - 8 * w - j] = in % 2; 
        in = in / 2; 
        j++; 
    } while (in != 0); 
    while (j <=8)   
    {
     
        md5[32 * s - 8 * w - j] = 0; 
        j++; 
    } 
} 
void dectobina_tail(int in, int *md5) 
{
     
    int i,j,temp, a[64]; 
    for (i = 0; in!= 0; i++) 
    {
     
        a[i] = in % 2; 
        in = in / 2; 
    } 
    while (i % 8 != 0) 
    {
     
        a[i] = 0; 
        i++; 
    } 
    for (j = 0; j <i/2; j++) 
    {
     
        temp = a[i - j - 1]; 
        a[i - j-1] = a[j]; 
        a[j] = temp; 
    } 
    temp = i/8; 
    for (i=i-1; i < 64; i++) 
        a[i] = 0; 
    for (i = 0; i < 4; i++)  
    {
     
        for (j = 0; j < 8; j++) 
            md5[512 - temp * 8 + j - 32] = a[i * 8 + j]; 
        temp = temp - 1; 
    } 
    for (i = 0; i < 4; i++) 
    {
     
        for (j = 0; j < 8; j++) 
            md5[512 - (i + 1) * 8 + j ] = a[i * 8 + j+32]; 
    } 
} 
void hextobina(char *t, int *temp) 
{
     
    int i; 
    for (i = 0; i < 8; i++) 
    {
     
        switch (t[i]) 
        {
     
        case '0':{
    temp[4 * i] = 0; temp[4 * i + 1] = 0; temp[4 * i + 2] = 0; temp[4 * i + 3] = 0; }break; 
        case '1':{
    temp[4 * i] = 0; temp[4 * i + 1] = 0; temp[4 * i + 2] = 0; temp[4 * i + 3] = 1; }break; 
        case '2':{
    temp[4 * i] = 0; temp[4 * i + 1] = 0; temp[4 * i + 2] = 1; temp[4 * i + 3] = 0; }break; 
        case '3':{
    temp[4 * i] = 0; temp[4 * i + 1] = 0; temp[4 * i + 2] = 1; temp[4 * i + 3] = 1; }break; 
        case '4':{
    temp[4 * i] = 0; temp[4 * i + 1] = 1; temp[4 * i + 2] = 0; temp[4 * i + 3] = 0; }break; 
        case '5':{
    temp[4 * i] = 0; temp[4 * i + 1] = 1; temp[4 * i + 2] = 0; temp[4 * i + 3] = 1; }break; 
        case '6':{
    temp[4 * i] = 0; temp[4 * i + 1] = 1; temp[4 * i + 2] = 1; temp[4 * i + 3] = 0; }break;  
        case '7':{
    temp[4 * i] = 0; temp[4 * i + 1] = 1; temp[4 * i + 2] = 1; temp[4 * i + 3] = 1; }break; 
        case '8':{
    temp[4 * i] = 1; temp[4 * i + 1] = 0; temp[4 * i + 2] = 0; temp[4 * i + 3] = 0; }break; 
        case '9':{
    temp[4 * i] = 1; temp[4 * i + 1] = 0; temp[4 * i + 2] = 0; temp[4 * i + 3] = 1; }break; 
        case 'a':{
    temp[4 * i] = 1; temp[4 * i + 1] = 0; temp[4 * i + 2] = 1; temp[4 * i + 3] = 0; }break; 
        case 'b':{
    temp[4 * i] = 1; temp[4 * i + 1] = 0; temp[4 * i + 2] = 1; temp[4 * i + 3] = 1; }break; 
        case 'c':{
    temp[4 * i] = 1; temp[4 * i + 1] = 1; temp[4 * i + 2] = 0; temp[4 * i + 3] = 0; }break; 
        case 'd':{
    temp[4 * i] = 1; temp[4 * i + 1] = 1; temp[4 * i + 2] = 0; temp[4 * i + 3] = 1; }break; 
        case 'e':{
    temp[4 * i] = 1; temp[4 * i + 1] = 1; temp[4 * i + 2] = 1; temp[4 * i + 3] = 0; }break; 
        case 'f':{
    temp[4 * i] = 1; temp[4 * i + 1] = 1; temp[4 * i + 2] = 1; temp[4 * i + 3] = 1; }break;    
        } 
    } 
} 
void c_out(int *a) 
{
     
    int i,add; 
    for (i = 1; i <= 4; i++)
    {
     
        add = a[32 - i * 8] * 8 + a[32 - i * 8 + 1] * 4 + a[32 - i * 8 + 2] * 2 + a[32 - i * 8 + 3]; 
        if (add >= 10) 
        {
     
            switch (add) 
            {
     
            case 10:printf("a"); break; 
            case 11:printf("b"); break; 
            case 12:printf("c"); break; 
            case 13:printf("d"); break; 
            case 14:printf("e"); break; 
            case 15:printf("f"); break; 
            } 
        } 
        else 
            printf("%d", add); 
        add = a[32 - i * 8+4] * 8 + a[32 - i * 8 + 5] * 4 + a[32 - i * 8 + 6] * 2 + a[32 - i * 8 + 7]; 
        if (add >= 10) 
        {
     
            switch (add) 
            {
     
            case 10:printf("a"); break; 
            case 11:printf("b"); break; 
            case 12:printf("c"); break; 
            case 13:printf("d"); break; 
            case 14:printf("e"); break; 
            case 15:printf("f"); break; 
            } 
        } 
        else 
            printf("%d", add); 
    } 
} 
void abcd_out(int *a) 
{
     
    int i, add; 
    for (i = 0; i < 4; i++) 
    {
     
        add = a[i * 8] * 8 + a[i * 8 + 1] * 4 + a[i * 8 + 2] * 2 + a[i * 8 + 3]; 
        if (add >= 10) 
        {
     
            switch (add) 
            {
     
            case 10:printf("a"); break; 
            case 11:printf("b"); break; 
            case 12:printf("c"); break; 
            case 13:printf("d"); break; 
            case 14:printf("e"); break; 
            case 15:printf("f"); break; 
            } 
        } 
        else 
            printf("%d", add); 
        add = a[i * 8 + 4] * 8 + a[i * 8 + 5] * 4 + a[i * 8 + 6] * 2 + a[i * 8 + 7]; 
        if (add >= 10) 
        {
     
            switch (add) 
            {
     
            case 10:printf("a"); break; 
            case 11:printf("b"); break; 
            case 12:printf("c"); break; 
            case 13:printf("d"); break; 
            case 14:printf("e"); break; 
            case 15:printf("f"); break; 
            } 
        } 
        else 
            printf("%d", add); 
    } 
} 
void and(int *a, int *b,int *temp) 
{
     
    int i; 
    for (i = 0; i < 32; i++) 
    {
     
        if (a[i] == 1 && b[i] == 1) 
            temp[i] = 1; 
        else 
            temp[i] = 0; 
    } 
} 
void or(int *a, int *b, int *temp) 
{
     
    int i; 
    for (i = 0; i < 32; i++) 
    {
     
        if (a[i] == 0 && b[i] == 0) 
            temp[i] = 0; 
        else 
            temp[i] = 1; 
    } 
} 
void no(int *a, int *temp) 
{
     
    int i; 
    for (i = 0; i < 32; i++)   
    {
     
        if (a[i] == 0) 
            temp[i] = 1; 
        else 
            temp[i] = 0; 
    } 
} 
void xor(int *a, int *b, int *temp) 
{
     
    int i; 
    for (i = 0; i < 32; i++)
    {
     
        if (a[i] != b[i]) 
            temp[i] = 1; 
        else 
            temp[i] = 0; 
    } 
} 
void addto(int *a, int *b, int *temp) 
{
     
    int i,jin; 
    jin = 0; 
    for (i = 0; i < 32; i++) 
    {
     
        if (a[31 - i] + b[31 - i] + jin>1) 
        {
     
            temp[31 - i] = a[31 - i] + b[31 - i] + jin - 2; 
            jin = 1; 
        } 
        else 
        {
     
            temp[31 - i] = a[31 - i] + b[31 - i]+jin; 
            jin = 0; 
        } 
    } 
} 
void F(int *b, int *c, int *d,int *temp1,int *temp2) 
{
     
  
    and(b, c, temp1); 
    no(b, temp2); 
    and(temp2, d, temp2); 
    or(temp1, temp2, temp2); 
} 
void G(int *b, int *c, int *d, int *temp1, int *temp2) 
{
     
  
    and(b, d, temp1); 
    no(d, temp2); 
    and(temp2, c, temp2); 
    or(temp1, temp2, temp2); 
} 
void H(int *b, int *c, int *d, int *temp) 
{
     
   
    xor(b, c, temp); 
    xor(temp, d, temp); 
} 
void I(int *b, int *c, int *d, int *temp) 
{
     
  
    no(d, temp); 
    or(b, temp, temp); 
    xor(c, temp, temp); 
} 
void move(int step, int *temp1, int *temp2) 
{
     
    int i; 
    for (i = 0; i < 32 - step; i++) 
        temp2[i] = temp1[i + step]; 
    for (i = 0; i < step; i++) 
        temp2[32 - step + i] = temp1[i]; 
} 
void round(int *a, int *b, int *c, int *d, int *m, int *md5, int r, char *t1,  
    char *t2, char *t3, char *t4, char *t5, char *t6, char *t7, char *t8, char *t9,  
    char *t10, char *t11, char *t12, char *t13, char *t14, char *t15, char *t16 ) 
{
     
    int i, j, in, step , temp1[32], temp2[32]; 
    for (i = 0; i < 16; i++) 
    {
     
        switch (r) 
        {
     
        case 1:F(b, c, d, temp1, temp2); break; 
        case 2:G(b, c, d, temp1, temp2); break; 
        case 3:H(b, c, d, temp2); break; 
        case 4:I(b, c, d, temp2); break; 
        } 
        in = m[i]; 
        for (j = 0; j < 32; j++) 
            temp1[j] = md5[in * 32 + j]; 
        addto(temp2, temp1, temp2); 
        switch (i + 1)  
        {
     
        case 1:hextobina(t1, temp1); break; 
        case 2:hextobina(t2, temp1); break; 
        case 3:hextobina(t3, temp1); break; 
        case 4:hextobina(t4, temp1); break; 
        case 5:hextobina(t5, temp1); break; 
        case 6:hextobina(t6, temp1); break; 
        case 7:hextobina(t7, temp1); break; 
        case 8:hextobina(t8, temp1); break; 
        case 9:hextobina(t9, temp1); break; 
        case 10:hextobina(t10, temp1); break; 
        case 11:hextobina(t11, temp1); break; 
        case 12:hextobina(t12, temp1); break; 
        case 13:hextobina(t13, temp1); break; 
        case 14:hextobina(t14, temp1); break; 
        case 15:hextobina(t15, temp1); break; 
        case 16:hextobina(t16, temp1); break; 
        } 
        addto(temp2, temp1, temp2); 
        addto(temp2, a, temp2); 
        switch(r)
        {
       
        case 1:switch (i % 4 + 1){
     case 1:step = 7; break; case 2:step = 12; break; case 3:step = 17; break; case 4:step = 22; break; }break; 
        case 2:switch (i % 4 + 1){
     case 1:step = 5; break; case 2:step = 9; break; case 3:step = 14; break; case 4:step = 20; break; }break; 
        case 3:switch (i % 4 + 1){
     case 1:step = 4; break; case 2:step = 11; break; case 3:step = 16; break; case 4:step = 23; break; }break; 
        case 4:switch (i % 4 + 1){
     case 1:step = 6; break; case 2:step = 10; break; case 3:step = 15; break; case 4:step = 21; break; }break; 
        } 
        move(step, temp2, temp1); 
        addto(temp1, b, temp2); 
        for (j = 0; j < 32; j++) 
        {
     
            a[j] = d[j]; 
            d[j] = c[j]; 
            c[j] = b[j]; 
            b[j] = temp2[j]; 
        } 
    } 
}
int main() 
{
     
    char ch,  
        t1[8] = {
     'd', '7', '6', 'a', 'a', '4', '7', '8' }, 
        t2[8] = {
     'e', '8', 'c', '7', 'b', '7', '5', '6' }, 
        t3[8] = {
     '2', '4', '2', '0', '7', '0', 'd', 'b' }, 
        t4[8] = {
     'c', '1', 'b', 'd', 'c', 'e', 'e', 'e' }, 
        t5[8] = {
     'f', '5', '7', 'c', '0', 'f', 'a', 'f' }, 
        t6[8] = {
     '4', '7', '8', '7', 'c', '6', '2', 'a' }, 
        t7[8] = {
     'a', '8', '3', '0', '4', '6', '1', '3' }, 
        t8[8] = {
     'f', 'd', '4', '6', '9', '5', '0', '1' }, 
        t9[8] = {
     '6', '9', '8', '0', '9', '8', 'd', '8' }, 
        t10[8] = {
     '8', 'b', '4', '4', 'f', '7', 'a', 'f' }, 
        t11[8] = {
     'f', 'f', 'f', 'f', '5', 'b', 'b', '1' }, 
        t12[8] = {
     '8', '9', '5', 'c', 'd', '7', 'b', 'e' }, 
        t13[8] = {
     '6', 'b', '9', '0', '1', '1', '2', '2' }, 
        t14[8] = {
     'f', 'd', '9', '8', '7', '1', '9', '3' }, 
        t15[8] = {
     'a', '6', '7', '9', '4', '3', '8', 'e' }, 
        t16[8] = {
     '4', '9', 'b', '4', '0', '8', '2', '1' }, 
        t17[8] = {
     'f', '6', '1', 'e', '2', '5', '6', '2' }, 
        t18[8] = {
     'c', '0', '4', '0', 'b', '3', '4', '0' }, 
        t19[8] = {
     '2', '6', '5', 'e', '5', 'a', '5', '1' }, 
        t20[8] = {
     'e', '9', 'b', '6', 'c', '7', 'a', 'a' }, 
        t21[8] = {
     'd', '6', '2', 'f', '1', '0', '5', 'd' }, 
        t22[8] = {
     '0', '2', '4', '4', '1', '4', '5', '3' }, 
        t23[8] = {
     'd', '8', 'a', '1', 'e', '6', '8', '1' }, 
        t24[8] = {
     'e', '7', 'd', '3', 'f', 'b', 'c', '8' }, 
        t25[8] = {
     '2', '1', 'e', '1', 'c', 'd', 'e', '6' }, 
        t26[8] = {
     'c', '3', '3', '7', '0', '7', 'd', '6' }, 
        t27[8] = {
     'f', '4', 'd', '5', '0', 'd', '8', '7' }, 
        t28[8] = {
     '4', '5', '5', 'a', '1', '4', 'e', 'd' }, 
        t29[8] = {
     'a', '9', 'e', '3', 'e', '9', '0', '5' }, 
        t30[8] = {
     'f', 'c', 'e', 'f', 'a', '3', 'f', '8' }, 
        t31[8] = {
     '6', '7', '6', 'f', '0', '2', 'd', '9' }, 
        t32[8] = {
     '8', 'd', '2', 'a', '4', 'c', '8', 'a' }, 
        t33[8] = {
     'f', 'f', 'f', 'a', '3', '9', '4', '2' }, 
        t34[8] = {
     '8', '7', '7', '1', 'f', '6', '8', '1' }, 
        t35[8] = {
     '6', 'd', '9', 'd', '6', '1', '2', '2' }, 
        t36[8] = {
     'f', 'd', 'e', '5', '3', '8', '0', 'c' }, 
        t37[8] = {
     'a', '4', 'b', 'e', 'e', 'a', '4', '4' }, 
        t38[8] = {
     '4', 'b', 'd', 'e', 'c', 'f', 'a', '9' }, 
        t39[8] = {
     'f', '6', 'b', 'b', '4', 'b', '6', '0' }, 
        t40[8] = {
     'b', 'e', 'b', 'f', 'b', 'c', '7', '0' }, 
        t41[8] = {
     '2', '8', '9', 'b', '7', 'e', 'c', '6' }, 
        t42[8] = {
     'e', 'a', 'a', '1', '2', '7', 'f', 'a' }, 
        t43[8] = {
     'd', '4', 'e', 'f', '3', '0', '8', '5' }, 
        t44[8] = {
     '0', '4', '8', '8', '1', 'd', '0', '5' }, 
        t45[8] = {
     'd', '9', 'd', '4', 'd', '0', '3', '9' }, 
        t46[8] = {
     'e', '6', 'd', 'b', '9', '9', 'e', '5' }, 
        t47[8] = {
     '1', 'f', 'a', '2', '7', 'c', 'f', '8' }, 
        t48[8] = {
     'c', '4', 'a', 'c', '5', '6', '6', '5' }, 
        t49[8] = {
     'f', '4', '2', '9', '2', '2', '4', '4' }, 
        t50[8] = {
     '4', '3', '2', 'a', 'f', 'f', '9', '7' }, 
        t51[8] = {
     'a', 'b', '9', '4', '2', '3', 'a', '7' }, 
        t52[8] = {
     'f', 'c', '9', '3', 'a', '0', '3', '9' }, 
        t53[8] = {
     '6', '5', '5', 'b', '5', '9', 'c', '3' }, 
        t54[8] = {
     '8', 'f', '0', 'c', 'c', 'c', '9', '2' }, 
        t55[8] = {
     'f', 'f', 'e', 'f', 'f', '4', '7', 'd' }, 
        t56[8] = {
     '8', '5', '8', '4', '5', 'd', 'd', '1' }, 
        t57[8] = {
     '6', 'f', 'a', '8', '7', 'e', '4', 'f' }, 
        t58[8] = {
     'f', 'e', '2', 'c', 'e', '6', 'e', '0' }, 
        t59[8] = {
     'a', '3', '0', '1', '4', '3', '1', '4' }, 
        t60[8] = {
     '4', 'e', '0', '8', '1', '1', 'a', '1' }, 
        t61[8] = {
     'f', '7', '5', '3', '7', 'e', '8', '2' }, 
        t62[8] = {
     'b', 'd', '3', 'a', 'f', '2', '3', '5' }, 
        t63[8] = {
     '2', 'a', 'd', '7', 'd', '2', 'b', 'b' }, 
        t64[8] = {
     'e', 'b', '8', '6', 'd', '3', '9', '1' }; 
    int in, n = 0, i,j,addup; 
    int md5[512], 
        m1[16] = {
     0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }, 
        m2[16] = {
     1, 6, 11, 0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12 }, 
        m3[16] = {
     5, 8, 11, 14, 1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15, 2 }, 
        m4[16] = {
     0, 7, 14, 5, 12, 3, 10, 1, 8, 15, 6, 13, 4, 11, 2, 9 }, 
        a[32] = {
     
0, 1, 1, 0, 0, 1, 1, 1, 
        0, 1, 0, 0, 0, 1, 0, 1, 
        0, 0, 1, 0, 0, 0, 1, 1, 
        0, 0, 0, 0, 0, 0, 0, 1 }, 
        a1[32] = {
     0, 1, 1, 0, 0, 1, 1, 1, 
        0, 1, 0, 0, 0, 1, 0, 1, 
        0, 0, 1, 0, 0, 0, 1, 1, 
        0, 0, 0, 0, 0, 0, 0, 1 }, 
        b[32] = {
     
1, 1, 1, 0, 1, 1, 1, 1, 
        1, 1, 0, 0, 1, 1, 0, 1, 
        1, 0, 1, 0, 1, 0, 1, 1, 
        1, 0, 0, 0, 1, 0, 0, 1 }, 
        b1[32] = {
     
1, 1, 1, 0, 1, 1, 1, 1, 
        1, 1, 0, 0, 1, 1, 0, 1, 
        1, 0, 1, 0, 1, 0, 1, 1, 
        1, 0, 0, 0, 1, 0, 0, 1 }, 
        c[32] = {
     
1, 0, 0, 1, 1, 0, 0, 0, 
        1, 0, 1, 1, 1, 0, 1, 0, 
        1, 1, 0, 1, 1, 1, 0, 0, 
        1, 1, 1, 1, 1, 1, 1, 0 }, 
        c1[32] = {
    
1, 0, 0, 1, 1, 0, 0, 0, 
        1, 0, 1, 1, 1, 0, 1, 0, 
        1, 1, 0, 1, 1, 1, 0, 0, 
        1, 1, 1, 1, 1, 1, 1, 0 }, 
        d[32] = {
     
0, 0, 0, 1, 0, 0, 0, 0, 
        0, 0, 1, 1, 0, 0, 1, 0, 
        0, 1, 0, 1, 0, 1, 0, 0, 
        0, 1, 1, 1, 0, 1, 1, 0 }, 
        d1[32] = {
     
0, 0, 0, 1, 0, 0, 0, 0, 
        0, 0, 1, 1, 0, 0, 1, 0, 
        0, 1, 0, 1, 0, 1, 0, 0, 
        0, 1, 1, 1, 0, 1, 1, 0 }; 
    printf("请输入需加密的明文(长度不大于56)\n"); 
    ch = getchar(); 
    while (ch!='\n'&&n<57)  
    {
     
        in = (int)ch; 
        dectobina(in, n, md5); 
        n++; 
        ch = getchar(); 
    } 
    i = 0; 
    addup = n; 
    while (n% 4 != 0 && n<56)   
    {
     
        int s, w, j; 
        s = n / 4 + 1; 
        w = n % 4; 
        j = 1; 
        do 
        {
     
            md5[32 * s - 8 * w - j] = 0; 
            j++; 
        } while (j<=7); 
        if (i == 0) 
        {
     
            md5[32 * s - 8 * w - j] = 1;   
            i = 1; 
        } 
        n++; 
    } 
    if (i == 0)  
    {
     
        for (j = 0; j < 32; j++) 
            md5[n * 8 + j] = 0; 
        md5[8 * n + 24] = 1; 
    } 
    for (i = 0; i < 512; i++)  
    {
     
        if (md5[i] == 1) 
            md5[i] = 1; 
        else 
            md5[i] = 0; 
    } 
    printf("\n"); 
    dectobina_tail(addup * 8, md5);  
    round(a, b, c, d, m1, md5, 1, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15, t16); 
    round(a, b, c, d, m2, md5, 2, t17, t18, t19, t20, t21, t22, t23, t24, t25, t26, t27, t28, t29, t30, t31, t32); 
    round(a, b, c, d, m3, md5, 3, t33, t34, t35, t36, t37, t38, t39, t40, t41, t42, t43, t44, t45, t46, t47, t48); 
    round(a, b, c, d, m4, md5, 4, t49, t50, t51, t52, t53, t54, t55, t56, t57, t58, t59, t60, t61, t62, t63, t64); 
    printf("\n"); 
    addto(a, a1, a); 
    addto(b, b1, b); 
    addto(c, c1, c); 
    addto(d, d1, d); 
    printf("密文:\n"); 
    c_out(a); 
    c_out(b); 
    c_out(c); 
    c_out(d); 
    printf("\n");
    system("pause");
    return 0; 
}

程序运行结果
输入明文:happy
程序运行结果
在这里插入图片描述
图 1 运行结果图

【实验思考题】

1.F、G、H、I四个函数的计算顺序可以打乱吗?为什么?
答:不可以。md5以512位分组来处理输入的信息,且每一分组又被划分为16个32位子分组,经过了一系列的处理后,算法的输出由四个32位分组组成,将这四个32位分组级联后将生成一个128位散列值。md5中有四个32位被称作链接变量(chaining variable)的整数参数,他们分别为:a=0x01234567,b=0x89abcdef,c=0xfedcba98,d=0x76543210。

当设置好这四个链接变量后,就开始进入算法的四轮循环运算。循环的次数是信息中512位信息分组的数目。
  将上面四个链接变量复制到另外四个变量中:a到a,b到b,c到c,d到d。
主循环有四轮(md4只有三轮),每轮循环都很相似。第一轮进行16次操作。每次操作对a、b、c和d中的其中三个作一次非线性函数运算,然后将所得结果加上第四个变量,文本的一个子分组和一个常数。再将所得结果向右环移一个不定的数,并加上a、b、c或d中之一。最后用该结果取代a、b、c或d中之一。
以一下是每次操作中用到的四个非线性函数(每轮一个)。

f(x,y,z) =(x&y)|((~x)&z)
   g(x,y,z) =(x&z)|(y&(~z))
   h(x,y,z) =xyz
   i(x,y,z)=y^(x|(~z))
   (&是与,|是或,~是非,^是异或)

F,G,H,I分别是:


DWORD md5::F(DWORD X,DWORD Y,DWORD Z){
    
	return (X&Y)|((~X)&Z);
}

DWORD md5::G(DWORD X,DWORD Y,DWORD Z){
	return (X&Z)|(Y&(~Z));
}
DWORD md5::H(DWORD X,DWORD Y,DWORD Z){
    
	return X^Y^Z;
}
DWORD md5::I(DWORD X,DWORD Y,DWORD Z){
    
	return Y^(X|(~Z));
}

这四个函数的说明:如果x、y和z的对应位是独立和均匀的,那么结果的每一位也应是独立和均匀的。
f是一个逐位运算的函数。即,如果x,那么y,否则z。函数h是逐位奇偶操作符。故不能改变。

2.MD5算法的一致性验证该如何实现?
MD5算法常常被用来验证网络文件传输的完整性,防止文件被人篡改。MD5 全称是报文摘要算法(Message-Digest Algorithm 5),此算法对任意长度的信息逐位进行计算,产生一个二进制长度为128位(十六进制长度就是32位)的“指纹”(或称“报文摘要”),不同的文件产生相同的报文摘要的可能性是非常非常之小的。
在linux或Unix上,md5sum是用来计算和校验文件报文摘要的工具程序。一般来说,安装了Linux后,就会有md5sum这个工具,直接在命令行终端直接运行。

2、命令格式
md5sum [OPTION]… [FILE]…
3、命令选项
-b 或 --binary :把输入文件作为二进制文件看待。
-t 或 --text :把输入的文件作为文本文件看待(默认)。
-c 或 --check :用来从文件中读取md5信息检查文件的一致性。(不细说了参见info)
–status :这个选项和check一起使用,在check的时候,不输出,而是根据返回值表示检查结果。
-w 或 --warn :在check的时候,检查输入的md5信息又没有非法的行,如果有则输出相应信息。
4、例子
(1)生产一个文件的md5值。
(2)检查两个文件是否一样,可以通过比较两个文件的md5值。
(3)判断一个文件是否修改,通过md5来判断

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_43717119/article/details/118059328

智能推荐

GCD介绍与总结_Nerazzur的博客-程序员ITS203

一、简单介绍1.什么是GCD?全称是Grand Central Dispatch,可译为“大中心调度”纯C语言,提供了非常多强大的函数 2.GCD的优势GCD是苹果公司为多核的并行运算提出的解决方案GCD会自动利用更多的CPU内核(比如双核、四核)GCD会自动管理线程的生命周期(创建线程、调度任务、销毁线程)程序员只需要告诉GCD想要执行什么任务,不需要编写任何

Spring定时器时间配置_从此沉默的博客-程序员ITS203

Quartz在Spring中动态设置cronExpression (spring设置动态定时任务)    2007-07-25 13:52    什么是动态定时任务:是由客户制定生成的,服务端只知道该去执行什么任务,但任务的定时是不确定的(是由客户制定)。    这样总不能修改配置文件每定制个定时任务就增加一个trigger吧,即便允许客户修改配置文件,但总需要重新启动we

台式计算机最常用的10总线是,2016年9月计算机一级考试题库_乐游西奥的博客-程序员ITS203

2016年9月计算机一级考试题库1、在计算机系统中,BUS的含义是()A、公共汽车B、网络传输C、总线D、主机2、10进制数127转换为8进制数是()A、157B、167C、177D、2073、键盘属于计算机的()A、显示设备B、通讯设备C、输入设备D、输出设备4、在计算机运行时,把程序和数据一样存放在内存中,这是1946年由()所领导的研究小组所正式提出并论证的。(WWW.nIuBB.NeT)A...

arm-linux交叉编译工具出现cannot open linker script file test:错误解决方法_九只太阳的博客-程序员ITS203

关于arm-linux交叉编译工具出现cannot open linker script file test:错误解决方法使用arm-none-linux-gnueabi-ld重新定位他们的数据,并绑定符号引用。编译的时候会出现下面这个问题。arm-none-linux-gnueabi-ld: cannot open linker script file test: 没有那个文件或目录。出现这个问题的原因是因为arm-none-linux-gnueabi-ld中的一个参数使用错误导致的。我写的ma

pcDuino上跑第一个Arduino程序_blink_我用国芯的博客-程序员ITS203

入手pcDuino有一段时间了,鼓起勇气刷了个官方最新lubuntu系统,开始我的arduino之旅。刚刚调通了第一个基于arduino语言的led闪烁程序,与大家分享。Arduino就这么简单,很好上手。目标:使接在pcduino上的led灯闪烁硬件连接:一个led灯+限流电阻,一端接5V,另一端接pcduino上的任一GPIO(0-13)一、搭建环境安装官方文档刷最新ubunt

随便推点

马踏棋盘(骑士周游列国)__贪心算法_viki_vv的博客-程序员ITS203

最近研究了马踏棋盘的问题,分享一下心得。问题描述:将国际象棋的骑士放置任意位置,使其按规则不重复走完所有的棋格。该问题的实质应该是:哈密顿路径的遍历。首先画图分析一下具体环境:如图所示,每个棋格有且仅有八个前进方向,标记为“1…8”,每个方向不一定合法(超出棋盘)这时可以用递归回溯的思想对路径进行探索,思路是:从方向1开始探索路径,一条路走到黑,发现走不了就回头走其他的路再具体点的...

五个步骤建立适合自己企业的优秀网站_weixin_34406086的博客-程序员ITS203

怎样设计一个适合自己企业的优秀网站呢?今天网站专家为大家介绍企业如何建站的五大步骤,希望能给您带来帮助: 一、做网站前期准备 1、关键字选择 首先,网站会有一个主题,比如我是做人才网的,又或者是做复读机或者其他等等。这个主题是你要先有的。 有个这个主题了。你就要准备发散思维了。想所有尽可能多的相关...

如何培养科研人员的科研思维,加入相关课程组?_科研小白 新人上路的博客-程序员ITS203

python matlab 深度学习 人工智能 科研可视化 图像处理 科研绘图 AI 课题组 神经网络、支持向量机、决策树、随机森林 群优 化算法,如遗传算法、蚁群算法、蝙蝠算法 心电、肌电、血压、血氧饱和度、惯性传感器等 生理信号采集 成分分析、随机投影、互信息、 非负矩阵分解、稀疏优化...

用css3实现拖拽小案例_小斯不斯的博客-程序员ITS203_css3拖拽

首先,给大家看一下拖拽的效果图:代码部分:&amp;lt;!DOCTYPE html&amp;gt;&amp;lt;html lang=&quot;en&quot;&amp;gt;&amp;lt;head&amp;gt; &amp;lt;meta charset=&quot;UTF-8&quot;&amp;gt; &amp;lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1

第一章 常见跨平台解决方案及Flutter架构_普通网友的博客-程序员ITS203_跨平台解决方案

近些年来,不断的有前端跨平台方案涌现出来,比如基于WebView的Cordova,还有渲染成原生控件的Reactive、Weex等,那么,这些跨平台方案有什么通用的实现思路呢,而Flutter的设计思路与他们的区别又是什么呢。带着这些疑问,本章将会介绍什么是跨平台,常见的跨平台方案有哪些,以及Flutter的实现方案。1.1 跨平台解决方案1.1.1什么是跨平台我们知道,CPU有不同的架构和指令集,上层也有不同的操作系统,一个系统的可执行文件在另一个系统上就是不可执行的,比如Windows的e.

Dsu on tree树上启发式合并经典例题算法代码剖析_DevourPower的博客-程序员ITS203

题目链接:E. Lomsat gelral树上启发式合并合并,初见这个名字,我和大部分人一样望文生义觉得应该是子树信息的合并使用了一种“启发式”,相当于区间操作的线段树的Lzay标志一般,仅仅启发而不去真的合并。然后我兴高采烈的学了一下发现其实就是一个暴力。一个优雅的暴力优化。dsu on tree,dsu就是并查集,直译为树上并查集。(某L称该算法为静态链分治。首先我们审视一下题目暴力的写法:对于每个子树开一个桶或者对每个子树都清空一次桶,然后暴力跑得出空间为N2N^2N2 或者时间为N2N^2