MD5加密算法

前言

  MD5(Message-Digest Algorithm),是一种信息摘要算法,将明文字符串经hash处理后,返回一个16字节的数组。

  MD5严格意义上不算一种加密算法,因为通常我们理解的加密,总是可以通过解密的方式来还原成我们需要的明文,但是经过Hash算法处理的明文,是不可还原的。

  所以,一般用MD5做数字签名,以确保信息的完整性、信息来源的可靠性。

 

源码解析

  示例明文:String s = "abcd";

  » 编码

   使用utf-8将source编码为一个字节数组,byte[] s = [97,98,99,100]; (字符a对应的十进制数是97)

  » 填充

    填充结果:待加密字节数组长度为 n*64.

    填充规则:首先填充1000 0000,即十进制的-128;后面位填充0;最后8字节,需要填充原字符串的位数(4 * 8 = 32bit)

    所以,示例的填充结果为:

          byte[64] buffer = [97,98,99,100,-128,0,0,0,0...0,32,0,0,0,0,0,0,0];

        long var3 = this.bytesProcessed << 3;
        int var5 = (int)this.bytesProcessed & 63;
        int var6 = var5 < 56 ? 56 - var5 : 120 - var5;
        this.engineUpdate(padding, 0, var6);
        ByteArrayAccess.i2bLittle4((int)var3, this.buffer, 56);
        ByteArrayAccess.i2bLittle4((int)(var3 >>> 32), this.buffer, 60);    

  » 分组、分块 

ByteArrayAccess.b2iLittle64(var1, var2, this.x);

    分组:每64字节为一组;

    分块:每4字节为一块;

    示例中,分组分块结果为 1组、16块,因为在java中一个int就是4字节,所以我们可以用一个长度为16的int数组来保存分块结果。

        int[16] x = [x0,x1,x2,...,x64,x65];

 

    这里有个小细节,就是如何将字节转换为int。

      97 对应的二进制表示为 0110 0001

      98 --------------   0110 0010

      99 --------------   0110 0011

      100--------------   0110 0100

    在转换为int的时候,要倒序拼接,即转换结果用二进制表示为:0110 0100 0110 0011 0110 0010 0110 0001

  » 摘要处理

  
  //A、B、C、D4个int型数值,是用来保存最后的摘要结果的,下面给出的值,是它们的默认值。
  void implReset() {
  int A = 1732584193;
  int B = -271733879;
  int C = -1732584194;
   int D = 271733878;
  }
  //进行摘要处理的4个非线性函数
  private
static int FF(int var0, int var1, int var2, int var3, int var4, int var5, int var6) { var0 += (var1 & var2 | ~var1 & var3) + var4 + var6; return (var0 << var5 | var0 >>> 32 - var5) + var1; } private static int GG(int var0, int var1, int var2, int var3, int var4, int var5, int var6) { var0 += (var1 & var3 | var2 & ~var3) + var4 + var6; return (var0 << var5 | var0 >>> 32 - var5) + var1; } private static int HH(int var0, int var1, int var2, int var3, int var4, int var5, int var6) { var0 += (var1 ^ var2 ^ var3) + var4 + var6; return (var0 << var5 | var0 >>> 32 - var5) + var1; } private static int II(int var0, int var1, int var2, int var3, int var4, int var5, int var6) { var0 += (var2 ^ (var1 | ~var3)) + var4 + var6; return (var0 << var5 | var0 >>> 32 - var5) + var1; }

  可以看到,每个函数都有7个入参,通过&、|、 <<  、 >>>等位运算符,对这7个参数值进行运算。

  var0 ~ var3的取值范围为 A、B、C、D;

  var4 取值范围为x;

  var5 取值范围为从固定的4个int中,轮流取值,并且每个函数的固定值不同;

  var6 貌似是个随机数,每次处理都不一样,在源码中是直接写死的;

  接下来,我们就可以看看,是如何运用这4个函数做摘要处理的。可以结合下面给出的流程图,理解源码。    

void implCompress(byte[] var1, int var2) {
        ByteArrayAccess.b2iLittle64(var1, var2, this.x);//可以忽略,功能就是上面说的分块过程
        int var3 = this.state[0];
        int var4 = this.state[1];
        int var5 = this.state[2];
        int var6 = this.state[3];
        var3 = FF(var3, var4, var5, var6, this.x[0], 7, -680876936);
        var6 = FF(var6, var3, var4, var5, this.x[1], 12, -389564586);
        var5 = FF(var5, var6, var3, var4, this.x[2], 17, 606105819);
        var4 = FF(var4, var5, var6, var3, this.x[3], 22, -1044525330);
        var3 = FF(var3, var4, var5, var6, this.x[4], 7, -176418897);
        var6 = FF(var6, var3, var4, var5, this.x[5], 12, 1200080426);
        var5 = FF(var5, var6, var3, var4, this.x[6], 17, -1473231341);
        var4 = FF(var4, var5, var6, var3, this.x[7], 22, -45705983);
        var3 = FF(var3, var4, var5, var6, this.x[8], 7, 1770035416);
        var6 = FF(var6, var3, var4, var5, this.x[9], 12, -1958414417);
        var5 = FF(var5, var6, var3, var4, this.x[10], 17, -42063);
        var4 = FF(var4, var5, var6, var3, this.x[11], 22, -1990404162);
        var3 = FF(var3, var4, var5, var6, this.x[12], 7, 1804603682);
        var6 = FF(var6, var3, var4, var5, this.x[13], 12, -40341101);
        var5 = FF(var5, var6, var3, var4, this.x[14], 17, -1502002290);
        var4 = FF(var4, var5, var6, var3, this.x[15], 22, 1236535329);
        var3 = GG(var3, var4, var5, var6, this.x[1], 5, -165796510);
        var6 = GG(var6, var3, var4, var5, this.x[6], 9, -1069501632);
        var5 = GG(var5, var6, var3, var4, this.x[11], 14, 643717713);
        var4 = GG(var4, var5, var6, var3, this.x[0], 20, -373897302);
        var3 = GG(var3, var4, var5, var6, this.x[5], 5, -701558691);
        var6 = GG(var6, var3, var4, var5, this.x[10], 9, 38016083);
        var5 = GG(var5, var6, var3, var4, this.x[15], 14, -660478335);
        var4 = GG(var4, var5, var6, var3, this.x[4], 20, -405537848);
        var3 = GG(var3, var4, var5, var6, this.x[9], 5, 568446438);
        var6 = GG(var6, var3, var4, var5, this.x[14], 9, -1019803690);
        var5 = GG(var5, var6, var3, var4, this.x[3], 14, -187363961);
        var4 = GG(var4, var5, var6, var3, this.x[8], 20, 1163531501);
        var3 = GG(var3, var4, var5, var6, this.x[13], 5, -1444681467);
        var6 = GG(var6, var3, var4, var5, this.x[2], 9, -51403784);
        var5 = GG(var5, var6, var3, var4, this.x[7], 14, 1735328473);
        var4 = GG(var4, var5, var6, var3, this.x[12], 20, -1926607734);
        var3 = HH(var3, var4, var5, var6, this.x[5], 4, -378558);
        var6 = HH(var6, var3, var4, var5, this.x[8], 11, -2022574463);
        var5 = HH(var5, var6, var3, var4, this.x[11], 16, 1839030562);
        var4 = HH(var4, var5, var6, var3, this.x[14], 23, -35309556);
        var3 = HH(var3, var4, var5, var6, this.x[1], 4, -1530992060);
        var6 = HH(var6, var3, var4, var5, this.x[4], 11, 1272893353);
        var5 = HH(var5, var6, var3, var4, this.x[7], 16, -155497632);
        var4 = HH(var4, var5, var6, var3, this.x[10], 23, -1094730640);
        var3 = HH(var3, var4, var5, var6, this.x[13], 4, 681279174);
        var6 = HH(var6, var3, var4, var5, this.x[0], 11, -358537222);
        var5 = HH(var5, var6, var3, var4, this.x[3], 16, -722521979);
        var4 = HH(var4, var5, var6, var3, this.x[6], 23, 76029189);
        var3 = HH(var3, var4, var5, var6, this.x[9], 4, -640364487);
        var6 = HH(var6, var3, var4, var5, this.x[12], 11, -421815835);
        var5 = HH(var5, var6, var3, var4, this.x[15], 16, 530742520);
        var4 = HH(var4, var5, var6, var3, this.x[2], 23, -995338651);
        var3 = II(var3, var4, var5, var6, this.x[0], 6, -198630844);
        var6 = II(var6, var3, var4, var5, this.x[7], 10, 1126891415);
        var5 = II(var5, var6, var3, var4, this.x[14], 15, -1416354905);
        var4 = II(var4, var5, var6, var3, this.x[5], 21, -57434055);
        var3 = II(var3, var4, var5, var6, this.x[12], 6, 1700485571);
        var6 = II(var6, var3, var4, var5, this.x[3], 10, -1894986606);
        var5 = II(var5, var6, var3, var4, this.x[10], 15, -1051523);
        var4 = II(var4, var5, var6, var3, this.x[1], 21, -2054922799);
        var3 = II(var3, var4, var5, var6, this.x[8], 6, 1873313359);
        var6 = II(var6, var3, var4, var5, this.x[15], 10, -30611744);
        var5 = II(var5, var6, var3, var4, this.x[6], 15, -1560198380);
        var4 = II(var4, var5, var6, var3, this.x[13], 21, 1309151649);
        var3 = II(var3, var4, var5, var6, this.x[4], 6, -145523070);
        var6 = II(var6, var3, var4, var5, this.x[11], 10, -1120210379);
        var5 = II(var5, var6, var3, var4, this.x[2], 15, 718787259);
        var4 = II(var4, var5, var6, var3, this.x[9], 21, -343485551);
        this.state[0] += var3;
        this.state[1] += var4;
        this.state[2] += var5;
        this.state[3] += var6;
}

      

  我们把最后的摘要结果记为int[] An,Bn,Cn,Dn,最后将int转换为字节数组,长度为16.此时MD5加密结束。一般我们还需要将字节数组,转换为16进制的字符串。  

        

    

  

 

posted @ 2019-01-23 17:00  meama  阅读(458)  评论(0编辑  收藏  举报