加密算法(一,sha1)

db4.png
密码学认知

认知
密码锁,古墓
天王盖地虎,。。。。。
美国的摩尔斯在1844年发明的,故也被叫做摩尔斯电码。
银行,手机,游戏

步骤
  1. 将消息摘要转换成位字符串

我们以“abc”字符串来说明问题,因为'a'=97, 'b'=98, 'c'=99,所以将其转换为位串后为:
01100001 01100010 01100011

  1. 对转换后的位字符串进行补位操作
    Sha-1算法标准规定,必须对消息摘要进行补位操作,即将输入的数据进行填充,使得数据长度对512求余的结果为448 ,填充比特位的最高位补一个1,其余的位补0,如果在补位之前已经满足对512取模余数为448,也要进行补位,在其后补一位1即可。 总之,补位是至少补一位,最多补512位,我们依然以“abc”为例,其补位过程如下:
    初始的信息摘要:01100001 01100010 01100011
    第一步补位: 01100001 01100010 01100011 1
    ..... ......
    补位最后一位: 01100001 01100010 01100011 10.......0(后面补了423个0)
    而后我们将补位操作后的信息摘要转换为十六进制,如下所示:
    61626380 00000000 00000000 00000000
    00000000 00000000 00000000 00000000
    00000000 00000000 00000000 00000000
    00000000 00000000

  2. 附加长度值
    在信息摘要后面附加64bit的信息,用来表示原始信息摘要的长度,在这步操作之后,信息报文便是512bit的倍数。通常来说用一个64位的数据表示原始消息的长度,如果消息长度不大于2^64,那么前32bit就为0,在进行附加长度值操作后,其“abc”数据报文即变成如下形式:
    61626380 00000000 00000000 00000000
    00000000 00000000 00000000 00000000
    00000000 00000000 00000000 00000000
    00000000 00000000 00000000 00000018
    因为“abc”占3个字节,即24位 ,换算为十六进制即为0x18

  3. 初始化缓存
    一个160位MD缓冲区用以保存中间和最终散列函数的结果。它可以表示为5个32位的寄存器(H0,H1,H2,H3,H4)。初始化为:
    H0 = 0x67452301
    H1 = 0xEFCDAB89
    H2 = 0x98BADCFE
    H3 = 0x10325476
    H4 = 0xC3D2E1F0
    大端存储模式:高位数据放在低地址,低位数据放在高地址

  4. 计算消息摘要

S函数
循环左移操作符Sn(x),x是一个字,也就是32bit大小的变量,n是一个整数且0<=n<=32。Sn(X) = (X<<n)OR(X>>32-n)
常量字k(0)、k(1)、...k(79)
Kt = 0x5A827999 (0 <= t <= 19)
Kt = 0x6ED9EBA1 (20 <= t <= 39)
Kt = 0x8F1BBCDC (40 <= t <= 59)
Kt = 0xCA62C1D6 (60 <= t <= 79)
非线性函数
所要用到的一系列函数
Ft(b,c,d) ((b&c)|((~b)&d)) (0 <= t <= 19)
Ft(b,c,d) (bcd) (20 <= t <= 39)
Ft(b,c,d) ((b&c)|(b&d)|(c&d)) (40 <= t <= 59)
Ft(b,c,d) (bcd) (60 <= t <= 79)
根据结果无法反推
开始计算摘要
计算需要一个缓冲区,由5个32位的字组成,还需要一个80个32位字的缓冲区。第一个5个字的缓冲区被标识为A,B,C,D,E。80个字的缓冲区被标识为W0, W1,..., W79
另外还需要一个一个字的TEMP缓冲区。
为了产生消息摘要,在补好位的数据中前16个字的数据块M1, M2,..., Mn
会依次进行处理,处理每个数据块Mi 包含80个步骤。
现在开始处理M1, M2, ... , Mn。为了处理 Mi,需要进行下面的步骤
(1). 将 Mi 分成 16 个字 W0, W1, ... , W15, W0 是最左边的字
(2). 对于 t = 16 到 79 令 Wt = S1(Wt-3 XOR Wt-8 XOR Wt- 14 XOR Wt-16).
(3). 令 A = H0, B = H1, C = H2, D = H3, E = H4.
(4) 对于 t = 0 到 79,执行下面的循环
TEMP = S5(A) + ft(B,C,D) + E + Wt + Kt;
E = D; D = C; C = S30(B); B = A; A = TEMP;
(5). 令 H0 = H0 + A, H1 = H1 + B, H2 = H2 + C, H3 = H3 + D, H4 = H4 + E.
在处理完所有的 Mn, 后,消息摘要是一个160位的字符串,以下面的顺序标识
H0 H1 H2 H3 H4.

代码
import org.junit.Test;

public class sha1 {

    //1.准备工作
    public static final int[] abcde = {
            0x67452301,
            0xEFCDAB89,
            0x98BADCFE,
            0x10325476,
            0xC3D2E1F0
    };

    //存储再要数据的数组 存放密文的 20个字节*8 = 160
    public static int[] h = new int[5];
    //计算过程中需要用到的临时数据存储数组
    public static int[] m = new int[80];

    //定于辅助方法

    /**
     * 将字符转换为16进制字符串
     */
    public static String byteToHexString(byte b) {
        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[(b >>> 4) & 0x0f];
        ob[1] = digit[b & 0x0f];
        String s = new String(ob);
        return s;
    }

    /**
     * 将字节数组转化为16进制字符串
     */
    public static String byteArrayToHexString(byte[] array) {
        String strDigest = "";
        for (int i = 0; i < array.length; i++) {
            strDigest += byteToHexString(array[i]);
        }
        return strDigest;
    }

    /**
     * 4字节数组转换为int i个byte合成到byteData[]中
     */
    public static 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字节数组 int分解到byte数组中
     */
    public static void intToByteArray(int intValue, byte[] byteData, int i) {
        byteData[i] = (byte) ((intValue >>> 24) & 0xff);
        byteData[i + 1] = (byte) ((intValue >>> 16) & 0xff);
        byteData[i + 2] = (byte) ((intValue >>> 8) & 0xff);
        byteData[i + 3] = (byte) (intValue & 0xff);
    }

    /*
    Ft(b,c,d)  ((b&c)|((~b)&d))    (0 <= t <= 19)
    Ft(b,c,d) (b^c^d)             (20 <= t <= 39)
    Ft(b,c,d) ((b&c)|(b&d)|(c&d))  (40 <= t <= 59)
    Ft(b,c,d) (b^c^d)               (60 <= t <= 79)
    */

    public static int f1(int x, int y, int z) {
        return (x & y) | (~x & z);
    }

    public static int f2(int x, int y, int z) {
        return x ^ y ^ z;
    }

    public static int f3(int x, int y, int z) {
        return (x & y) | (x & z) | (y & z);
    }

    public static int f4(int x, int y, int z) {
        return x ^ y ^ z;
    }

    //n是一个整数且0<=n<=32。Sn(X) = (X<<n)OR(X>>(32-n))
    public static int s(int x,int i){
       return (x<<i) | (x>>>(32-i));
    }

    /**
     * 开始逻辑
     * <p>
     * 进行对原数据的补位
     */
    public static byte[] byteArrayFormatData(byte[] byteData) {
        //补0的位数
        int fill = 0;
        //补位后的总位数,64的倍数
        int size = 0;
        //原数据长度
        int srcLength = byteData.length;
        //对64求余
        int m = srcLength % 64;
        if (m < 56) {
            fill = 55 - m;
            size = srcLength - m + 64;
        } else if (m == 56) {
            fill = 63;
            size = srcLength + 8 + 64;
        } else {
            fill = 63 - m + 56;
            size = (srcLength + 64) - m + 64;
        }
        //补位后生成的新数组的内容
        byte[] newByte = new byte[size];
        System.arraycopy(byteData, 0, newByte, 0, srcLength);

        //补1
        int startLocation = srcLength;
        newByte[startLocation++] = (byte) 0x80;

        //补0
        for (int i = 0; i < fill; i++) {
            newByte[startLocation++] = (byte) 0x00;
        }

        //处理长度的位置
        long n = (long)srcLength*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[startLocation++] = h1;
        newByte[startLocation++] = h2;
        newByte[startLocation++] = h3;
        newByte[startLocation++] = h4;
        newByte[startLocation++] = h5;
        newByte[startLocation++] = h6;
        newByte[startLocation++] = h7;
        newByte[startLocation++] = h8;

        return newByte;
    }

    /**
     * 开始计算密文,算摘要
     */
    public static int process_input_bytes(byte[] byteData){
        System.arraycopy(abcde,0,h,0,abcde.length);
        //格式化数据
        byte[] newbyte = byteArrayFormatData(byteData);
        //计算有多少个大块
        int mCount = newbyte.length/64;
        //循环计算每一块的内容
        for (int post = 0; post < mCount; post++) {
            //对每一块都进行加密计算
            //(1). 将 Mi 分成 16 个字 W0, W1, ... , W15,  W0 是最左边的字
            for (int i = 0; i < 16; i++) {
                m[i] = byteArrayToInt(newbyte,(post*64)+(i*4));
            }
            //计算
            encrypt();
        }
        return 20;
    }

    private static void encrypt() {
        //(2). 对于 t = 16 到 79 令
        // Wt = S1(Wt-3 XOR Wt-8 XOR Wt- 14 XOR Wt-16).
        for (int t = 16; t <= 79 ; t++) {
            m[t] = s(m[t-3]^m[t-8]^m[t-14]^m[t-16],1);
        }
        //3.令 A = H0, B = H1, C = H2, D = H3, E = H4.
        int[] tempabcde = new int[5];
        for (int i = 0; i < tempabcde.length; i++) {
            tempabcde[i] = h[i];
        }
        //4.对于 t = 0 到 79,执行下面的循环
        //TEMP = S5(A) + ft(B,C,D) + E + Wt + Kt;
        //E = D; D = C; C = S30(B); B = A; A = TEMP;
        //一共有80次操作
        //Kt = 0x5A827999  (0 <= t <= 19)
//        Kt = 0x6ED9EBA1 (20 <= t <= 39)
//        Kt = 0x8F1BBCDC (40 <= t <= 59)
//        Kt = 0xCA62C1D6 (60 <= t <= 79)
        for (int i = 0; i <= 19; i++) {
            int temp = s(tempabcde[0],5)
                    +f1(tempabcde[1],tempabcde[2],tempabcde[3])
                    +tempabcde[4]
                    +m[i]
                    +0x5A827999;
            tempabcde[4] = tempabcde[3];
            tempabcde[3] = tempabcde[2];
            tempabcde[2] = s(tempabcde[1],30);
            tempabcde[1] = tempabcde[0];
            tempabcde[0] = temp;
        }
        for (int i = 20; i <= 39; i++) {
            int temp=s(tempabcde[0],5)
                    +f2(tempabcde[1],tempabcde[2],tempabcde[3])
                    +tempabcde[4]
                    +m[i]+0x6ED9EBA1;
            tempabcde[4]=tempabcde[3];
            tempabcde[3]=tempabcde[2];
            tempabcde[2]=s(tempabcde[1],30);
            tempabcde[1]=tempabcde[0];
            tempabcde[0]=temp;
        }
        for (int i = 40; i <= 59; i++) {
            int temp=s(tempabcde[0],5)
                    +f3(tempabcde[1],tempabcde[2],tempabcde[3])
                    +tempabcde[4]
                    +m[i]+0x8F1BBCDC;
            tempabcde[4]=tempabcde[3];
            tempabcde[3]=tempabcde[2];
            tempabcde[2]=s(tempabcde[1],30);
            tempabcde[1]=tempabcde[0];
            tempabcde[0]=temp;
        }
        for (int i = 60; i <= 79; i++) {
            int temp=s(tempabcde[0],5)
                    +f4(tempabcde[1],tempabcde[2],tempabcde[3])
                    +tempabcde[4]
                    +m[i]+0xCA62C1D6;
            tempabcde[4]=tempabcde[3];
            tempabcde[3]=tempabcde[2];
            tempabcde[2]=s(tempabcde[1],30);
            tempabcde[1]=tempabcde[0];
            tempabcde[0]=temp;
        }
        //5.令 H0 = H0 + A, H1 = H1 + B, H2 = H2 + C, H3 = H3 + D, H4 = H4 + E.
        for (int i = 0; i < tempabcde.length; i++) {
            h[i] = h[i] + tempabcde[i];
        }
        //完成了一次操作,清除之前的内容,开始计算下一块
        for (int i = 0; i < m.length; i++) {
            m[i] = 0;
        }
    }

    //把已经算好的数据提供一个接口,进行输入和输出
    public static byte[] getDigestOfBytes(byte[] byteData){
        process_input_bytes(byteData);
        byte[] digest = new byte[20];
        for (int i = 0; i < h.length; i++) {
            intToByteArray(h[i],digest,i*4);
        }
        return digest;
    }

    public static String getDigestOfString(byte[] byteData){
        return byteArrayToHexString(getDigestOfBytes(byteData));
    }

    @Test
    public void test(){
        String param="jett";
        System.out.println("加密前:"+param);
        String digest=getDigestOfString(param.getBytes());
        System.out.println("加密后的结果:"+digest);
    }
}

同类算法

SHA1 SHA224 SHA256 SHA384 SHA512 MD5 HmacMD5 HmacSHA1 HmacSHA224 HmacSHA256 HmacSHA384 HmacSHA512 PBKDF2

注意:

只要是哈希函数,就存在碰撞
所谓碰撞的意思是,有两个不同的数据,他们的哈希值相同(SHA1值相同)

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,905评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,140评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,791评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,483评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,476评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,516评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,905评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,560评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,778评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,557评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,635评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,338评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,925评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,898评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,142评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,818评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,347评论 2 342

推荐阅读更多精彩内容

  • 专业考题类型管理运行工作负责人一般作业考题内容选项A选项B选项C选项D选项E选项F正确答案 变电单选GYSZ本规程...
    小白兔去钓鱼阅读 8,970评论 0 13
  • 目前MaxMind对MMDB的读写支持如下Writer:perlReader:CC#JavaPerlPHPPyth...
    openex阅读 8,264评论 0 0
  • 加密算法的分类 对称加密采用对称秘钥的加密系统,加密、解密过程均采用同一把秘钥,通信双方必须同时获得这把钥匙进行加...
    静香头很痛阅读 3,854评论 0 6
  • 。。。
    花懿懿阅读 152评论 0 0
  • 何为天道,万物之律也。 生存之律,弱肉强食,适者生存也。 发展之律,脚踏实地,拾阶而上也。 修性之律,知其所欲,不...
    沐羽名生阅读 201评论 0 0