设为首页收藏本站帮助中心
查看: 6617|回复: 14
收起左侧

C51/STC单片机MD5算法正式版V2.0 (解决老版本占大量内存) 只占百字节RAM与2KB多ROM

[复制链接]
发表于 2019-9-4 18:07:16 | 显示全部楼层 |阅读模式
本帖最后由 哒哒哒 于 2019-9-4 18:05 编辑
md5("Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!")=2348fbde8521869a98337279f55711b5
Build target '目标 1'
compiling md5.c...
linking...
Program Size: data=90.3 xdata=64 code=2203
creating hex file from "MD5"...
"MD5" - 0 Error(s), 0 Warning(s).
V2.0        版本修订历史:
        修改只读速度(向左移位数) 为二维数组
        取消只读数组 (分组下标) 改为公式生成
        取消部分函数与全局变量(数组) 并修改部分全局变量为局部变量
        对算法进行优化 明文长度不限 只占用64字节片外RAM (XRAM)(XDATA)
        (V1.0版会将所有明文填入XRAM并大量占用空间,且计算长度有限)


(本程序不包含串口程序)被蓝色包含的内存区域就是计算出的MD5值:
图1.png

  1. /*

  2. V2.0        版本修订历史:
  3.         修改只读速度(向左移位数) 为二维数组
  4.         取消只读数组 (分组下标) 改为公式生成
  5.         取消部分函数与全局变量(数组) 并修改部分全局变量为局部变量
  6.         对算法进行优化 明文长度不限 只占用64字节片外RAM (XRAM)(XDATA)
  7.         (V1.0版会将所有明文填入XRAM并大量占用空间,且计算长度有限)

  8. */

  9. #include "reg51.h"
  10. #include "intrins.h"
  11. #include "stdio.h"
  12. #define U8 unsigned char
  13. #define U16 unsigned int
  14. #define U32 unsigned long
  15. sfr AUXR   = 0x8E;
  16. union md5_key {                //MD5答案分组
  17.         U32 l[4];
  18.         U8 c[16];
  19. };


  20. union md5_data {                //MD5数据分组
  21.         U32 l[16];                //16个32位分组
  22.         U8 c[64];                //64个8位分组
  23. };

  24. union udata {                        //32位大小端转换专用分组
  25.         U32 l;
  26.         U8 c[4];
  27. };

  28. //--------只读数组--------
  29. U32 code ti[]={                        //常量ti
  30.         0xd76aa478,0xe8c7b756,0x242070db,0xc1bdceee,
  31.         0xf57c0faf,0x4787c62a,0xa8304613,0xfd469501,0x698098d8,
  32.         0x8b44f7af,0xffff5bb1,0x895cd7be,0x6b901122,0xfd987193,
  33.         0xa679438e,0x49b40821,0xf61e2562,0xc040b340,0x265e5a51,
  34.         0xe9b6c7aa,0xd62f105d,0x02441453,0xd8a1e681,0xe7d3fbc8,
  35.         0x21e1cde6,0xc33707d6,0xf4d50d87,0x455a14ed,0xa9e3e905,
  36.         0xfcefa3f8,0x676f02d9,0x8d2a4c8a,0xfffa3942,0x8771f681,
  37.         0x6d9d6122,0xfde5380c,0xa4beea44,0x4bdecfa9,0xf6bb4b60,
  38.         0xbebfbc70,0x289b7ec6,0xeaa127fa,0xd4ef3085,0x04881d05,
  39.         0xd9d4d039,0xe6db99e5,0x1fa27cf8,0xc4ac5665,0xf4292244,
  40.         0x432aff97,0xab9423a7,0xfc93a039,0x655b59c3,0x8f0ccc92,
  41.         0xffeff47d,0x85845dd1,0x6fa87e4f,0xfe2ce6e0,0xa3014314,
  42.         0x4e0811a1,0xf7537e82,0xbd3af235,0x2ad7d2bb,0xeb86d391
  43.         };

  44. U8 code ss[4][4]={                //向左移位数
  45.         {7,12,17,22},
  46.         {5,9,14,20},
  47.         {4,11,16,23},
  48.         {6,10,15,21}
  49. };

  50. U32 rib32(U32 l){                //32位大小端转换(十六进制整数0x12345678,反转后将返回0x78563412)
  51.         union udata j,k;
  52.         U8 m;
  53.         j.l=l;
  54.         for(m=0;m<4;m++){
  55.                 k.c[m]=j.c[m^3];
  56.                 }
  57.         return k.l;
  58. }

  59. union md5_key md5_bin(U8 *i){                //计算字符串MD5值 (返回值类型为union md5_key结构的二进制MD5)
  60.         union md5_key md5_key;
  61.         union md5_data xdata md;
  62.         U32 A,B,C,D,aa,bb,cc,dd;        //MD5计算时需要用到的8个整数变量
  63.         U32 z,g,pc=0,len=0,gn;
  64.         U8 a,c,r,m;
  65.         bit f,s128=0;
  66.         //--------初始化MD5的4个变量--------
  67.         md5_key.l[0]=0x67452301;
  68.         md5_key.l[1]=0xefcdab89;   
  69.         md5_key.l[2]=0x98badcfe;
  70.         md5_key.l[3]=0x10325476;

  71.         for(;*i!=0;i++) len++;        //统计字符串总长度
  72.         gn=((len+8)>>6)+1;        //计算块数
  73.         i-=len;                        //指针位置减去总长度,否则会读到其他无用数据

  74.                 for(z=1;z<=gn;z++){        //变量z:块计数
  75.                         for(c=0;c<64;c++){                //变量C从0加到63
  76.                         f=pc>=len;                        //PC指针大于等于总长度时f为1,否则为0
  77.                         a=pc&63^3;                        //A指针等于PC指针的低6位再异或(取反)低2位用于反转大小端
  78.                         md.c[a] = f ? 0 : *i++;                //位变量f为1时送回0,否则将字符串送MD5数据分组
  79.                         if(f && !s128){                        //f为1 且 没有执行标记128(最后一个分组进行)       
  80.                                  s128=1;                        //标记128已经写入数据分组
  81.                                 md.c[a]=128;                //将128写入数据分组
  82.                         }
  83.                         pc++;
  84.                 }

  85.         if(z == gn) {                //最后一块,添加位长
  86.                 md.l[14]=len;md.l[15]=0;        //添加字节数到MD5数据分组
  87.                 for(a=0;a<3;a++){                //字节数带进位左移3位(乘8)即为位数
  88.                 f=0;                                //此处位变量f是进位标志

  89.                 for(c=56;c<64;c++){                //参与左移的为分组最后8字节
  90.                 m=md.c[c^3];        //将数据分组送入变量m (地址异或3用于大小端反转读取)
  91.                 r=m<<1|f;        //移位结果 (m左移1位再补上进位f)
  92.                 f=m>>7;                //进位结果 (m的最高位)
  93.                 md.c[c^3]=r;        //将变量r的值送回MD5数据分组
  94.                         }
  95.                 }
  96.                 }

  97.                 //--------MD5核心算法(循环次数为变量gn的值)--------
  98.         A=md5_key.l[0];B=md5_key.l[1];
  99.         C=md5_key.l[2];D=md5_key.l[3];
  100.         for(a=0;a<64;a++){
  101.                 switch(a>>4){
  102.                 case 0:{g=(B&C)|((~B)&D);c=a;break;}
  103.                 case 1:{g=(D&B)|((~D)&C);c=5*a+1;break;}
  104.                 case 2:{g=B^C^D;c=3*a+5;break;}
  105.                 case 3:{g=C^(B|(~D));c=7*a;break;}
  106.                 }
  107.         A=B+_lrol_(A+g+md.l[c&15]+ti[a],ss[a>>4][a&3]);        // _lrol_() 为 intrins.h 自带的32位整数循环左移函数
  108.                 aa=A;bb=B;cc=C;dd=D;
  109.                 A=dd;B=aa;C=bb;D=cc;
  110.         }
  111.         md5_key.l[0]+=A;md5_key.l[1]+=B;
  112.         md5_key.l[2]+=C;md5_key.l[3]+=D;
  113.                 }

  114.                 for(c=0;c<4;c++){        //计算完成对MD5答案分组进行大小端转换
  115.                         md5_key.l[c]=rib32(md5_key.l[c]);
  116.                         }
  117.         return md5_key;
  118. }


  119. //将union md5_key结构转换成文本MD5字符串 参数1: union md5_key结构 参数2:1大写0小写
  120. U8* md5_to_text(union md5_key md5_key,bit u){
  121.         U8 y[33];
  122.         U8 a,r=0,m;
  123.         bit f=0;
  124.         y[32]=0;
  125.         for(a=0;a<32;a+=2){
  126.                 do {
  127.                 m= f ? md5_key.c[r]&15 : md5_key.c[r]>>4;
  128.                 y[a+(U8)f]=(m <10?48:u?55:87)+m;
  129.                 f=!f;
  130.                 } while(f);
  131.                 r++;
  132.         }
  133.         return y;
  134. }

  135. U8* md5(U8 *i,bit u){        //计算字符串的MD5值 参数1:明文文本 参数2:1大写0小写 (返回16进制MD5字符串)
  136.         return md5_to_text(md5_bin(i),u);
  137. }



  138. void main(){
  139. md5("Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!",1);


  140. P3=0xAA;
  141. while(1);
  142. }
复制代码

评分

1

查看全部评分

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 加入我们

本版积分规则