zoukankan      html  css  js  c++  java
  • 接触到的加密算法MD5、SHA1(转)

     

    参考链接:

      https://blog.csdn.net/u012611878/article/details/54000607

      https://blog.csdn.net/worm0527/article/details/69939307

      https://blog.csdn.net/qq_32714913/article/details/50358204

    Hash,一般翻译做"散列",也有直接音译为"哈希"的,就是把任意长度的输入,变换成固定长度的输出,该输出就是散列值。这种转换是一种压缩映射,也就是,散列值的空间通常远小于输入的空间,不同的输入可能会散列成相同的输出,而不可能从散列值来唯一的确定输入值。简单的说就是一种将任意长度的消息压缩到某一固定长度的消息摘要的函数。
    MD5与SHA1都是Hash算法,MD5输出是128位的,SHA1输出是160位的,MD5比SHA1快,SHA1比MD5强度高。

    Hash是一种特殊的算法,MD5就是其中常用的一种。它的算法的特征是不可逆性,并且才计算的时候所有的数据都参与了运算,其中任何一个数据变化了都会导致计算出来的Hash值完全不同,所以通常用来校验数据是否正确或用作身份验证。常见的,论坛里面用户的密码是经过MD5等Hash算法算出来的Hash值进行保存的。

    MD5

    概述:

      (message digest arithmetic)消息摘要算法,一种被广泛使用的密码杂凑函数,可以产生出一个128位元(16位元组)的散列值,用于确保信息传输完整一致

    功能:

      输入任意长度的信息,经过处理输出为128位的信息;

      不同的输入得到不同的结果

    安全与不可逆:

    MD5没有解密算法。MD5不可逆的原因是其实一种散列函数,使用的是hash算法,在计算过程中原文的部分信息是丢失了的。

    一个MD5理论上的确是可能对应无数多个原文的,因为MD5是有限多个的而原文可以是无数多个。比如主流使用的MD5将任意长度的“字节串映射为一个128bit的大整数。也就是一共有2^128种可能,大概是3.4*10^38,这个数字是有限多个的,而但是世界上可以被用来加密的原文则会有无数的可能性。目前,MD5最有效的攻击方式就是彩虹表,穷举方式。

    用途:

      1、防止被修改,一段时间前后物品MD5不变说明它未被篡改

      2、防止直接看明文,比如密码的存储

      3、数字签名

    算法过程:

    对MD5算法简要的叙述可以为:MD5以512位分组来处理输入的信息,且每一分组又被划分为16个32位子分组,经过了一系列的处理后,算法的输出由四个32位分组组成,将这四个32位分组级联后将生成一个128位散列值。
    
    第一步、填充:如果输入信息的长度(bit)对512求余的结果不等于448,就需要填充使得对512求余的结果等于448。填充的方法是填充一个1和n个0。填充完后,信息的长度就为N*512+448(bit);
    
    第二步、记录信息长度:用64位来存储填充前信息长度。这64位加在第一步结果的后面,这样信息长度就变为N*512+448+64=(N+1)*512位。
    
    第三步、装入标准的幻数(四个整数):标准的幻数(物理顺序)是(A=(01234567)16,B=(89ABCDEF)16,C=(FEDCBA98)16,D=(76543210)16)。如果在程序中定义应该是: 
    (A=0X67452301L,B=0XEFCDAB89L,C=0X98BADCFEL,D=0X10325476L)。有点晕哈,其实想一想就明白了。
    
    第四步、四轮循环运算:循环的次数是分组的个数(N+11)将每一512字节细分成16个小组,每个小组64位(8个字节)
    
    2)先认识四个线性函数(&是与,|是或,~是非,^是异或)
    
    F(X,Y,Z)=(X&Y)|((~X)&Z)
    G(X,Y,Z)=(X&Z)|(Y&(~Z))
    H(X,Y,Z)=X^Y^Z
    I(X,Y,Z)=Y^(X|(~Z))
    1
    2
    3
    4
    3)设Mj表示消息的第j个子分组(从0到15),<<
    
    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)
    1
    2
    3
    4
    4)四轮运算
    
     第一轮
    a=FF(a,b,c,d,M0,7,0xd76aa478)
    b=FF(d,a,b,c,M1,12,0xe8c7b756)
    c=FF(c,d,a,b,M2,17,0x242070db)
    d=FF(b,c,d,a,M3,22,0xc1bdceee)
    a=FF(a,b,c,d,M4,7,0xf57c0faf)
    b=FF(d,a,b,c,M5,12,0x4787c62a)
    c=FF(c,d,a,b,M6,17,0xa8304613)
    d=FF(b,c,d,a,M7,22,0xfd469501)
    a=FF(a,b,c,d,M8,7,0x698098d8)
    b=FF(d,a,b,c,M9,12,0x8b44f7af)
    c=FF(c,d,a,b,M10,17,0xffff5bb1)
    d=FF(b,c,d,a,M11,22,0x895cd7be)
    a=FF(a,b,c,d,M12,7,0x6b901122)
    b=FF(d,a,b,c,M13,12,0xfd987193)
    c=FF(c,d,a,b,M14,17,0xa679438e)
    d=FF(b,c,d,a,M15,22,0x49b40821)
    
    第二轮
    a=GG(a,b,c,d,M1,5,0xf61e2562)
    b=GG(d,a,b,c,M6,9,0xc040b340)
    c=GG(c,d,a,b,M11,14,0x265e5a51)
    d=GG(b,c,d,a,M0,20,0xe9b6c7aa)
    a=GG(a,b,c,d,M5,5,0xd62f105d)
    b=GG(d,a,b,c,M10,9,0x02441453)
    c=GG(c,d,a,b,M15,14,0xd8a1e681)
    d=GG(b,c,d,a,M4,20,0xe7d3fbc8)
    a=GG(a,b,c,d,M9,5,0x21e1cde6)
    b=GG(d,a,b,c,M14,9,0xc33707d6)
    c=GG(c,d,a,b,M3,14,0xf4d50d87)
    d=GG(b,c,d,a,M8,20,0x455a14ed)
    a=GG(a,b,c,d,M13,5,0xa9e3e905)
    b=GG(d,a,b,c,M2,9,0xfcefa3f8)
    c=GG(c,d,a,b,M7,14,0x676f02d9)
    d=GG(b,c,d,a,M12,20,0x8d2a4c8a)
    
    第三轮
    a=HH(a,b,c,d,M5,4,0xfffa3942)
    b=HH(d,a,b,c,M8,11,0x8771f681)
    c=HH(c,d,a,b,M11,16,0x6d9d6122)
    d=HH(b,c,d,a,M14,23,0xfde5380c)
    a=HH(a,b,c,d,M1,4,0xa4beea44)
    b=HH(d,a,b,c,M4,11,0x4bdecfa9)
    c=HH(c,d,a,b,M7,16,0xf6bb4b60)
    d=HH(b,c,d,a,M10,23,0xbebfbc70)
    a=HH(a,b,c,d,M13,4,0x289b7ec6)
    b=HH(d,a,b,c,M0,11,0xeaa127fa)
    c=HH(c,d,a,b,M3,16,0xd4ef3085)
    d=HH(b,c,d,a,M6,23,0x04881d05)
    a=HH(a,b,c,d,M9,4,0xd9d4d039)
    b=HH(d,a,b,c,M12,11,0xe6db99e5)
    c=HH(c,d,a,b,M15,16,0x1fa27cf8)
    d=HH(b,c,d,a,M2,23,0xc4ac5665)
    
    第四轮
    a=II(a,b,c,d,M0,6,0xf4292244)
    b=II(d,a,b,c,M7,10,0x432aff97)
    c=II(c,d,a,b,M14,15,0xab9423a7)
    d=II(b,c,d,a,M5,21,0xfc93a039)
    a=II(a,b,c,d,M12,6,0x655b59c3)
    b=II(d,a,b,c,M3,10,0x8f0ccc92)
    c=II(c,d,a,b,M10,15,0xffeff47d)
    d=II(b,c,d,a,M1,21,0x85845dd1)
    a=II(a,b,c,d,M8,6,0x6fa87e4f)
    b=II(d,a,b,c,M15,10,0xfe2ce6e0)
    c=II(c,d,a,b,M6,15,0xa3014314)
    d=II(b,c,d,a,M13,21,0x4e0811a1)
    a=II(a,b,c,d,M4,6,0xf7537e82)
    b=II(d,a,b,c,M11,10,0xbd3af235)
    c=II(c,d,a,b,M2,15,0x2ad7d2bb)
    d=II(b,c,d,a,M9,21,0xeb86d391)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    5)每轮循环后,将A,B,C,D分别加上a,b,c,d,然后进入下一循环。
    
    如果上面的过程用JAVA代码来实现的话,代码如下:
    
    public class MD5 {
    
        static final String hexs[]={"0","1","2","3","4","5","6","7","8","9","A","B","C","D","E","F"};
        //标准的幻数
        private static final long A=0x67452301L;
        private static final long B=0xefcdab89L;
        private static final long C=0x98badcfeL;
        private static final long D=0x10325476L;
    
    
        //下面这些S11-S44实际上是一个4*4的矩阵,在四轮循环运算中用到
        static final int S11 = 7;
        static final int S12 = 12;
        static final int S13 = 17;
        static final int S14 = 22;
    
        static final int S21 = 5;
        static final int S22 = 9;
        static final int S23 = 14;
        static final int S24 = 20;
    
        static final int S31 = 4;
        static final int S32 = 11;
        static final int S33 = 16;
        static final int S34 = 23;
    
        static final int S41 = 6;
        static final int S42 = 10;
        static final int S43 = 15;
        static final int S44 = 21;
    
        //java不支持无符号的基本数据(unsigned)
        private long [] result={A,B,C,D};//存储hash结果,共4×32=128位,初始化值为(幻数的级联)
    
        public static void main(String []args){
            MD5 md=new MD5();
            System.out.println("md5(abc)="+md.digest("abc"));
        }
    
        private String digest(String inputStr){
            byte [] inputBytes=inputStr.getBytes();
            int byteLen=inputBytes.length;//长度(字节)
            int groupCount=0;//完整分组的个数
            groupCount=byteLen/64;//每组512位(64字节)
            long []groups=null;//每个小组(64字节)再细分后的16个小组(4字节)
    
            //处理每一个完整 分组
            for(int step=0;step<groupCount;step++){
                groups=divGroup(inputBytes,step*64);
                trans(groups);//处理分组,核心算法
            }
    
            //处理完整分组后的尾巴
            int rest=byteLen%64;//512位分组后的余数
            byte [] tempBytes=new byte[64];
            if(rest<=56){
                for(int i=0;i<rest;i++)
                    tempBytes[i]=inputBytes[byteLen-rest+i];
                if(rest<56){
                    tempBytes[rest]=(byte)(1<<7);
                    for(int i=1;i<56-rest;i++)
                        tempBytes[rest+i]=0;
                }
                long len=(long)(byteLen<<3);
                for(int i=0;i<8;i++){
                    tempBytes[56+i]=(byte)(len&0xFFL);
                    len=len>>8;
                }
                groups=divGroup(tempBytes,0);
                trans(groups);//处理分组
            }else{
                for(int i=0;i<rest;i++)
                    tempBytes[i]=inputBytes[byteLen-rest+i];
                tempBytes[rest]=(byte)(1<<7);
                for(int i=rest+1;i<64;i++)
                    tempBytes[i]=0;
                groups=divGroup(tempBytes,0);
                trans(groups);//处理分组
    
                for(int i=0;i<56;i++)
                    tempBytes[i]=0;
                long len=(long)(byteLen<<3);
                for(int i=0;i<8;i++){
                    tempBytes[56+i]=(byte)(len&0xFFL);
                    len=len>>8;
                }
                groups=divGroup(tempBytes,0);
                trans(groups);//处理分组
            }
    
            //将Hash值转换成十六进制的字符串
            String resStr="";
            long temp=0;
            for(int i=0;i<4;i++){
                for(int j=0;j<4;j++){
                    temp=result[i]&0x0FL;
                    String a=hexs[(int)(temp)];
                    result[i]=result[i]>>4;
                    temp=result[i]&0x0FL;
                    resStr+=hexs[(int)(temp)]+a;
                    result[i]=result[i]>>4;
                }
            }
            return resStr;
        }
    
        /**
         * 从inputBytes的index开始取512位,作为新的分组
         * 将每一个512位的分组再细分成16个小组,每个小组64位(8个字节)
         * @param inputBytes
         * @param index
         * @return
         */
        private static long[] divGroup(byte[] inputBytes,int index){
            long [] temp=new long[16];
            for(int i=0;i<16;i++){
                temp[i]=b2iu(inputBytes[4*i+index])|
                    (b2iu(inputBytes[4*i+1+index]))<<8|
                    (b2iu(inputBytes[4*i+2+index]))<<16|
                    (b2iu(inputBytes[4*i+3+index]))<<24;
            }
            return temp;
        }
    
        /**
         * 这时不存在符号位(符号位存储不再是代表正负),所以需要处理一下
         * @param b
         * @return
         */
        public static long b2iu(byte b){
            return b < 0 ? b & 0x7F + 128 : b;
         }
    
        /**
         * 主要的操作,四轮循环
         * @param groups[]--每一个分组512位(64字节)
         */
        private void trans(long[] groups) {
            long a = result[0], b = result[1], c = result[2], d = result[3];
            /*第一轮*/
            a = FF(a, b, c, d, groups[0], S11, 0xd76aa478L); /* 1 */
            d = FF(d, a, b, c, groups[1], S12, 0xe8c7b756L); /* 2 */
            c = FF(c, d, a, b, groups[2], S13, 0x242070dbL); /* 3 */
            b = FF(b, c, d, a, groups[3], S14, 0xc1bdceeeL); /* 4 */
            a = FF(a, b, c, d, groups[4], S11, 0xf57c0fafL); /* 5 */
            d = FF(d, a, b, c, groups[5], S12, 0x4787c62aL); /* 6 */
            c = FF(c, d, a, b, groups[6], S13, 0xa8304613L); /* 7 */
            b = FF(b, c, d, a, groups[7], S14, 0xfd469501L); /* 8 */
            a = FF(a, b, c, d, groups[8], S11, 0x698098d8L); /* 9 */
            d = FF(d, a, b, c, groups[9], S12, 0x8b44f7afL); /* 10 */
            c = FF(c, d, a, b, groups[10], S13, 0xffff5bb1L); /* 11 */
            b = FF(b, c, d, a, groups[11], S14, 0x895cd7beL); /* 12 */
            a = FF(a, b, c, d, groups[12], S11, 0x6b901122L); /* 13 */
            d = FF(d, a, b, c, groups[13], S12, 0xfd987193L); /* 14 */
            c = FF(c, d, a, b, groups[14], S13, 0xa679438eL); /* 15 */
            b = FF(b, c, d, a, groups[15], S14, 0x49b40821L); /* 16 */
    
            /*第二轮*/
            a = GG(a, b, c, d, groups[1], S21, 0xf61e2562L); /* 17 */
            d = GG(d, a, b, c, groups[6], S22, 0xc040b340L); /* 18 */
            c = GG(c, d, a, b, groups[11], S23, 0x265e5a51L); /* 19 */
            b = GG(b, c, d, a, groups[0], S24, 0xe9b6c7aaL); /* 20 */
            a = GG(a, b, c, d, groups[5], S21, 0xd62f105dL); /* 21 */
            d = GG(d, a, b, c, groups[10], S22, 0x2441453L); /* 22 */
            c = GG(c, d, a, b, groups[15], S23, 0xd8a1e681L); /* 23 */
            b = GG(b, c, d, a, groups[4], S24, 0xe7d3fbc8L); /* 24 */
            a = GG(a, b, c, d, groups[9], S21, 0x21e1cde6L); /* 25 */
            d = GG(d, a, b, c, groups[14], S22, 0xc33707d6L); /* 26 */
            c = GG(c, d, a, b, groups[3], S23, 0xf4d50d87L); /* 27 */
            b = GG(b, c, d, a, groups[8], S24, 0x455a14edL); /* 28 */
            a = GG(a, b, c, d, groups[13], S21, 0xa9e3e905L); /* 29 */
            d = GG(d, a, b, c, groups[2], S22, 0xfcefa3f8L); /* 30 */
            c = GG(c, d, a, b, groups[7], S23, 0x676f02d9L); /* 31 */
            b = GG(b, c, d, a, groups[12], S24, 0x8d2a4c8aL); /* 32 */
    
            /*第三轮*/
            a = HH(a, b, c, d, groups[5], S31, 0xfffa3942L); /* 33 */
            d = HH(d, a, b, c, groups[8], S32, 0x8771f681L); /* 34 */
            c = HH(c, d, a, b, groups[11], S33, 0x6d9d6122L); /* 35 */
            b = HH(b, c, d, a, groups[14], S34, 0xfde5380cL); /* 36 */
            a = HH(a, b, c, d, groups[1], S31, 0xa4beea44L); /* 37 */
            d = HH(d, a, b, c, groups[4], S32, 0x4bdecfa9L); /* 38 */
            c = HH(c, d, a, b, groups[7], S33, 0xf6bb4b60L); /* 39 */
            b = HH(b, c, d, a, groups[10], S34, 0xbebfbc70L); /* 40 */
            a = HH(a, b, c, d, groups[13], S31, 0x289b7ec6L); /* 41 */
            d = HH(d, a, b, c, groups[0], S32, 0xeaa127faL); /* 42 */
            c = HH(c, d, a, b, groups[3], S33, 0xd4ef3085L); /* 43 */
            b = HH(b, c, d, a, groups[6], S34, 0x4881d05L); /* 44 */
            a = HH(a, b, c, d, groups[9], S31, 0xd9d4d039L); /* 45 */
            d = HH(d, a, b, c, groups[12], S32, 0xe6db99e5L); /* 46 */
            c = HH(c, d, a, b, groups[15], S33, 0x1fa27cf8L); /* 47 */
            b = HH(b, c, d, a, groups[2], S34, 0xc4ac5665L); /* 48 */
    
            /*第四轮*/
            a = II(a, b, c, d, groups[0], S41, 0xf4292244L); /* 49 */
            d = II(d, a, b, c, groups[7], S42, 0x432aff97L); /* 50 */
            c = II(c, d, a, b, groups[14], S43, 0xab9423a7L); /* 51 */
            b = II(b, c, d, a, groups[5], S44, 0xfc93a039L); /* 52 */
            a = II(a, b, c, d, groups[12], S41, 0x655b59c3L); /* 53 */
            d = II(d, a, b, c, groups[3], S42, 0x8f0ccc92L); /* 54 */
            c = II(c, d, a, b, groups[10], S43, 0xffeff47dL); /* 55 */
            b = II(b, c, d, a, groups[1], S44, 0x85845dd1L); /* 56 */
            a = II(a, b, c, d, groups[8], S41, 0x6fa87e4fL); /* 57 */
            d = II(d, a, b, c, groups[15], S42, 0xfe2ce6e0L); /* 58 */
            c = II(c, d, a, b, groups[6], S43, 0xa3014314L); /* 59 */
            b = II(b, c, d, a, groups[13], S44, 0x4e0811a1L); /* 60 */
            a = II(a, b, c, d, groups[4], S41, 0xf7537e82L); /* 61 */
            d = II(d, a, b, c, groups[11], S42, 0xbd3af235L); /* 62 */
            c = II(c, d, a, b, groups[2], S43, 0x2ad7d2bbL); /* 63 */
            b = II(b, c, d, a, groups[9], S44, 0xeb86d391L); /* 64 */
    
            /*加入到之前计算的结果当中*/
            result[0] += a;
            result[1] += b;
            result[2] += c;
            result[3] += d;
            result[0]=result[0]&0xFFFFFFFFL;
            result[1]=result[1]&0xFFFFFFFFL;
            result[2]=result[2]&0xFFFFFFFFL;
            result[3]=result[3]&0xFFFFFFFFL;
        }
    
        /**
         * 下面是处理要用到的线性函数
         */
        private static long F(long x, long y, long z) {
            return (x & y) | ((~x) & z);
        }
    
        private static long G(long x, long y, long z) {
            return (x & z) | (y & (~z));
        }
    
        private static long H(long x, long y, long z) {
            return x ^ y ^ z;
        }
    
        private static long I(long x, long y, long z) {
            return y ^ (x | (~z));
        }
    
        private static long FF(long a, long b, long c, long d, long x, long s,
                long ac) {
            a += (F(b, c, d)&0xFFFFFFFFL) + x + ac;
            a = ((a&0xFFFFFFFFL)<< s) | ((a&0xFFFFFFFFL) >>> (32 - s));
            a += b;
            return (a&0xFFFFFFFFL);
        }
    
        private static long GG(long a, long b, long c, long d, long x, long s,
                long ac) {
            a += (G(b, c, d)&0xFFFFFFFFL) + x + ac;
            a = ((a&0xFFFFFFFFL) << s) | ((a&0xFFFFFFFFL) >>> (32 - s));
            a += b;
            return (a&0xFFFFFFFFL);
        }
    
        private static long HH(long a, long b, long c, long d, long x, long s,
                long ac) {
            a += (H(b, c, d)&0xFFFFFFFFL) + x + ac;
            a = ((a&0xFFFFFFFFL) << s) | ((a&0xFFFFFFFFL) >>> (32 - s));
            a += b;
            return (a&0xFFFFFFFFL);
        }
    
        private static long II(long a, long b, long c, long d, long x, long s,
                long ac) {
            a += (I(b, c, d)&0xFFFFFFFFL) + x + ac;
            a = ((a&0xFFFFFFFFL) << s) | ((a&0xFFFFFFFFL) >>> (32 - s));
            a += b;
            return (a&0xFFFFFFFFL);
        }
    }
    View Code

    Java的实现:

      算法过程我是看不太懂,Java的面向对象思想不错,Java中也提供了进行MD5加密的对象。

      包java.security有个类MessageDigest。官方文档如下:

        此 MessageDigest 类为应用程序提供信息摘要算法的功能,如 MD5 或 SHA 算法。信息摘要是安全的单向哈希函数,它接收任意大小的数据,并输出固定长度的哈希值。

             MessageDigest 对象开始被初始化。该对象通过使用 update 方法处理数据。任何时候都可以调用 reset 方法重置摘要。一旦所有需要更新的数据都已经被更新了,应该调用 digest 方法之一完成哈希计算。

              对于给定数量的更新数据,digest 方法只能被调用一次。在调用 digest 之后,MessageDigest 对象被重新设置成其初始状态。 

       

     public static void main(String[] args) {try{
                MessageDigest md5 = MessageDigest.getInstance("MD5");
                md5.update("abc".getBytes());
                System.out.println("md5(abc)=" + byte2HexStr(md5.digest()));
            }catch (NoSuchAlgorithmException e){
    
            }
    
        }

    这里注意:得到的输出结果一般展示为16进制的字符串,而不是简单的new String(bytes). 好像说16进制是通用的加密表示方法。

    byte[]与16进制字符串的转换:

    package kunpu.arithmetic.encryption;
    
    /**
     * @author zhen
     * @Date 2018/4/4 10:29
     */
    public class Byte2Hex {
        private final static char[] hexDigits = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
    
        /**
         * 方法一
         * @param b
         * @return
         */
        private static String byteArrayToHexString(byte[] b) {
            StringBuffer resultSb = new StringBuffer();
            for (int i = 0; i < b.length; i++) {
                resultSb.append(byteToHexString(b[i]));
            }
            return resultSb.toString();
        }
        private static String byteToHexString(byte b) {
            int n = b;
            if (n < 0) n = 256 + n;
            int d1 = n / 16;
            int d2 = n % 16;
            return "" + hexDigits[d1] + hexDigits[d2];
        }
    
        /**
         * 方法二:
         * byte[] to hex string
         *
         * @param bytes
         * @return
         */
        public static String bytesToHexFun2(byte[] bytes) {
            char[] buf = new char[bytes.length * 2];
            int index = 0;
            for(byte b : bytes) { // 利用位运算进行转换,可以看作方法一的变种
                buf[index++] = hexDigits[b >>> 4 & 0xf];
                buf[index++] = hexDigits[b & 0xf];
            }
    
            return new String(buf);
        }
    
        /**
         * 方法三:
         * byte[] to hex string
         *
         * @param bytes
         * @return
         */
        public static String bytesToHexFun3(byte[] bytes) {
            StringBuilder buf = new StringBuilder(bytes.length * 2);
            for(byte b : bytes) { // 使用String的format方法进行转换
                buf.append(String.format("%02x", new Integer(b & 0xff)));
            }
            return buf.toString();
        }
    
        /**
         * 将16进制字符串转换为byte[]
         *
         * @param str
         * @return
         */
        public static byte[] toBytes(String str) {
            if(str == null || str.trim().equals("")) {
                return new byte[0];
            }
    
            byte[] bytes = new byte[str.length() / 2];
            for(int i = 0; i < str.length() / 2; i++) {
                String subStr = str.substring(i * 2, i * 2 + 2);
                bytes[i] = (byte) Integer.parseInt(subStr, 16);
            }
    
            return bytes;
        }
    
    }
    View Code

    SHA家族

    概述:

      安全散列算法(英语:Secure Hash Algorithm,缩写为SHA)是一个密码散列函数家族,是FIPS所认证的安全散列算法。能计算出一个数字消息所对应到的,长度固定的字符串(又称消息摘要)的算法。且若输入的消息不同,它们对应到不同字符串的机率很高。

    SHA(Security Hash Algorithm)是美国的NIST和NSA设计的一种标准的Hash算法,SHA用于数字签名的标准算法的DSS中,也是安全性很高的一种Hash算法,该算法的输入消息长度小于2^64bit,最终输出的结果值是160bit

    算法的Java实现:

    package kunpu.arithmetic.encryption;
    
    import javax.crypto.Mac;
    import javax.crypto.spec.SecretKeySpec;
    import java.security.InvalidKeyException;
    import java.security.MessageDigest;
    import java.security.NoSuchAlgorithmException;
    
    /**
     * @author zhen
     * @Date 2018/4/4 10:50
     */
    public class SHA1Simulate {
        private final int[] abcde = {0x67452301, 0xefcdab89, 0x98badcfe,
            0x10325476, 0xc3d2e1f0};
        // 摘要数据存储数组 
        private int[] digestInt = new int[5];
        // 计算过程中的临时数据存储数组 
        private int[] tmpData = new int[80];
    
        // 计算sha-1摘要 
        private int process_input_bytes(byte[] bytedata) {
            // 初试化常量
            System.arraycopy(abcde, 0, digestInt, 0, abcde.length);
            // 格式化输入字节数组,补10及长度数据
            byte[] newbyte = byteArrayFormatData(bytedata);
            // 获取数据摘要计算的数据单元个数
            int MCount = newbyte.length / 64;
            // 循环对每个数据单元进行摘要计算
            for (int pos = 0; pos < MCount; pos++) {
                // 将每个单元的数据转换成16个整型数据,并保存到tmpData的前16个数组元素中
                for (int j = 0; j < 16; j++) {
                    tmpData[j] = byteArrayToInt(newbyte, (pos * 64) + (j * 4));
                }
                //摘要计算函数
                encrypt();
            }
            return 20;
        }
    
        // 格式化输入字节数组格式 
        private byte[] byteArrayFormatData(byte[] bytedata) {
            // 补0数量
            int zeros = 0;
            // 补位后总位数
            int size = 0;
            // 原始数据长度
            int n = bytedata.length;
            // 模64后的剩余位数
            int m = n % 64;
            // 计算添加0的个数以及添加10后的总长度
            if (m < 56) {
                zeros = 55 - m;
                size = n - m + 64;
            } else if (m == 56) {
                zeros = 63;
                size = n + 8 + 64;
            } else {
                zeros = 63 - m + 56;
                size = (n + 64) - m + 64;
            }
            // 补位后生成的新数组内容
            byte[] newbyte = new byte[size];
            // 复制数组的前面部分
            System.arraycopy(bytedata, 0, newbyte, 0, n);
            // 获得数组Append数据元素的位置
            int l = n;
            // 补1操作
            newbyte[l++] = (byte) 0x80;
            // 补0操作
            for (int i = 0; i < zeros; i++) {
                newbyte[l++] = (byte) 0x00;
            }
            // 计算数据长度,补数据长度位共8字节,长整型
            long N = (long) n * 8;
            byte h8 = (byte) (N & 0xFF);
            byte h7 = (byte) ((N >> 8) & 0xFF);
            byte h6 = (byte) ((N >> 16) & 0xFF);
            byte h5 = (byte) ((N >> 24) & 0xFF);
            byte h4 = (byte) ((N >> 32) & 0xFF);
            byte h3 = (byte) ((N >> 40) & 0xFF);
            byte h2 = (byte) ((N >> 48) & 0xFF);
            byte h1 = (byte) (N >> 56);
            newbyte[l++] = h1;
            newbyte[l++] = h2;
            newbyte[l++] = h3;
            newbyte[l++] = h4;
            newbyte[l++] = h5;
            newbyte[l++] = h6;
            newbyte[l++] = h7;
            newbyte[l++] = h8;
            return newbyte;
        }
    
        private int f1(int x, int y, int z) {
            return (x & y) | (~x & z);
        }
    
        private int f2(int x, int y, int z) {
            return x ^ y ^ z;
        }
    
        private int f3(int x, int y, int z) {
            return (x & y) | (x & z) | (y & z);
        }
    
        private int f4(int x, int y) {
            return (x << y) | x >>> (32 - y);
        }
    
        //单元摘要计算函数
        private void encrypt() {
            for (int i = 16; i <= 79; i++) {
                tmpData[i] = f4(tmpData[i - 3] ^ tmpData[i - 8] ^ tmpData[i - 14]
                    ^ tmpData[i - 16], 1);
            }
            int[] tmpabcde = new int[5];
            for (int i1 = 0; i1 < tmpabcde.length; i1++) {
                tmpabcde[i1] = digestInt[i1];
            }
            for (int j = 0; j <= 19; j++) {
                int tmp = f4(tmpabcde[0], 5)
                    + f1(tmpabcde[1], tmpabcde[2], tmpabcde[3]) + tmpabcde[4]
                    + tmpData[j] + 0x5a827999;
                tmpabcde[4] = tmpabcde[3];
                tmpabcde[3] = tmpabcde[2];
                tmpabcde[2] = f4(tmpabcde[1], 30);
                tmpabcde[1] = tmpabcde[0];
                tmpabcde[0] = tmp;
            }
            for (int k = 20; k <= 39; k++) {
                int tmp = f4(tmpabcde[0], 5)
                    + f2(tmpabcde[1], tmpabcde[2], tmpabcde[3]) + tmpabcde[4]
                    + tmpData[k] + 0x6ed9eba1;
                tmpabcde[4] = tmpabcde[3];
                tmpabcde[3] = tmpabcde[2];
                tmpabcde[2] = f4(tmpabcde[1], 30);
                tmpabcde[1] = tmpabcde[0];
                tmpabcde[0] = tmp;
            }
            for (int l = 40; l <= 59; l++) {
                int tmp = f4(tmpabcde[0], 5)
                    + f3(tmpabcde[1], tmpabcde[2], tmpabcde[3]) + tmpabcde[4]
                    + tmpData[l] + 0x8f1bbcdc;
                tmpabcde[4] = tmpabcde[3];
                tmpabcde[3] = tmpabcde[2];
                tmpabcde[2] = f4(tmpabcde[1], 30);
                tmpabcde[1] = tmpabcde[0];
                tmpabcde[0] = tmp;
            }
            for (int m = 60; m <= 79; m++) {
                int tmp = f4(tmpabcde[0], 5)
                    + f2(tmpabcde[1], tmpabcde[2], tmpabcde[3]) + tmpabcde[4]
                    + tmpData[m] + 0xca62c1d6;
                tmpabcde[4] = tmpabcde[3];
                tmpabcde[3] = tmpabcde[2];
                tmpabcde[2] = f4(tmpabcde[1], 30);
                tmpabcde[1] = tmpabcde[0];
                tmpabcde[0] = tmp;
            }
            for (int i2 = 0; i2 < tmpabcde.length; i2++) {
                digestInt[i2] = digestInt[i2] + tmpabcde[i2];
            }
            for (int n = 0; n < tmpData.length; n++) {
                tmpData[n] = 0;
            }
        }
    
        // 4字节数组转换为整数 
        private int byteArrayToInt(byte[] bytedata, int i) {
            return ((bytedata[i] & 0xff) << 24) | ((bytedata[i + 1] & 0xff) << 16)
                | ((bytedata[i + 2] & 0xff) << 8) | (bytedata[i + 3] & 0xff);
        }
    
        // 整数转换为4字节数组 
        private void intToByteArray(int intValue, byte[] byteData, int i) {
            byteData[i] = (byte) (intValue >>> 24);
            byteData[i + 1] = (byte) (intValue >>> 16);
            byteData[i + 2] = (byte) (intValue >>> 8);
            byteData[i + 3] = (byte) intValue;
        }
    
        // 将字节转换为十六进制字符串 
        private static String byteToHexString(byte ib) {
            char[] Digit = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A',
                'B', 'C', 'D', 'E', 'F'};
            char[] ob = new char[2];
            ob[0] = Digit[(ib >>> 4) & 0X0F];
            ob[1] = Digit[ib & 0X0F];
            String s = new String(ob);
            return s;
        }
    
        // 将字节数组转换为十六进制字符串 
        private static String byteArrayToHexString(byte[] bytearray) {
            String strDigest = "";
            for (int i = 0; i < bytearray.length; i++) {
                strDigest += byteToHexString(bytearray[i]);
            }
            return strDigest;
        }
    
        // 计算sha-1摘要,返回相应的字节数组 
        public byte[] getDigestOfBytes(byte[] byteData) {
            process_input_bytes(byteData);
            byte[] digest = new byte[20];
            for (int i = 0; i < digestInt.length; i++) {
                intToByteArray(digestInt[i], digest, i * 4);
            }
            return digest;
        }
    
        // 计算sha-1摘要,返回相应的十六进制字符串 
        public String getDigestOfString(byte[] byteData) {
            return byteArrayToHexString(getDigestOfBytes(byteData));
        }
    
        //测试
        public static void main(String[] args) {
            String param = "wxzzs";
            System.out.println("加密前:" + param);
            String digest = new SHA1Simulate().getDigestOfString(param.getBytes());
            System.out.println("加密后:" + digest);
    
            try {
                MessageDigest messageDigest = MessageDigest.getInstance("sha1");
                messageDigest.update(param.getBytes());
                String digest1 = byteArrayToHexString(messageDigest.digest());
                System.out.println("加密后:" + digest1);
            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
            }
        }
    
    }
    View Code

    其实我不懂实现,嘿嘿。面向对象,Java MessageDigest类:

     try {
                MessageDigest messageDigest = MessageDigest.getInstance("sha1");
                messageDigest.update(param.getBytes());
                String digest1 = byteArrayToHexString(messageDigest.digest());
                System.out.println("加密后:" + digest1);
            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
            }

    最近接阿里接口加密使用的是sha1算法

  • 相关阅读:
    Docker搭建持续集成平台Jenkins
    Selenium Webdriver 架构
    JMeter性能监控系统:Jmeter + InfluxDB + Grafana
    持续集成平台Jenkins配置方法介绍
    perl中的map
    Smarty 配置文件中的相对路径
    挑出IIS日志里某一文件的请求次数
    写PHP,内伤中....
    File::Find
    强制删除删除不了的文件
  • 原文地址:https://www.cnblogs.com/aigeileshei/p/8716306.html
Copyright © 2011-2022 走看看