在Java中从头开始实现SHA-1

在Java中从头开始实现SHA-1,java,hash,sha,Java,Hash,Sha,我一直试图通过遵循我在网上找到的wikipedia伪代码和幻灯片在Java中实现SHA-1,但与在线实现的值相比,我得到的哈希值不正确(例如) 我有两个功能。一种预处理函数,它接受一个字符串并返回一个列表列表,其中外部列表表示512位的块,内部列表每个包含80个32位的字。我经历了所描述的获取消息的二进制值的过程,添加一个,用零填充,直到长度为-64 mod 512,然后添加原始消息的长度(位数),然后作为64位值添加/填充到二进制字符串的末尾。这给了我512的倍数。将它们分成512位的块,每个

我一直试图通过遵循我在网上找到的wikipedia伪代码和幻灯片在Java中实现SHA-1,但与在线实现的值相比,我得到的哈希值不正确(例如)

我有两个功能。一种预处理函数,它接受一个字符串并返回一个列表列表,其中外部列表表示512位的块,内部列表每个包含80个32位的字。我经历了所描述的获取消息的二进制值的过程,添加一个,用零填充,直到长度为-64 mod 512,然后添加原始消息的长度(位数),然后作为64位值添加/填充到二进制字符串的末尾。这给了我512的倍数。将它们分成512位的块,每个块分成32位的16个字。然后使用XOR添加单词,直到每个块有80个单词

第二个函数循环遍历块和单词,然后根据在线伪代码更改h变量。然而,当涉及到生成最终散列时,似乎有些地方说只连接五个h变量,而其他来源说进行旋转和/或它们。下面的代码不适用于追加,因为它会生成80位的散列值(即假定大小的两倍),但使用旋转,然后ORing会给出不正确的值。我不知道下一步该做什么,我找不到任何合适的在线实现

注意:关于旋转的距离,我把它除以四,根据我的理解,这是在十六进制而不是二进制字符串上应用左旋转的正确方法

private static ArrayList<ArrayList<String>> preprocessing(String s){
        String binary_message = "";
        for(int i = 0 ;i<s.length();i++){
            binary_message+= toBinary8((int) s.charAt(i));
        }

        int msg_len = binary_message.length();
        binary_message+="1";

        while(binary_message.length()%512 != 448){
            binary_message = "0"+binary_message;
        }

        binary_message+=toBinary64(msg_len);

        System.out.println(binary_message.length());

        ArrayList<String> chunks = new ArrayList<String>();
        for(int i = 0 ; i<binary_message.length()/512 ; i++){
            chunks.add(binary_message.substring(i*512, (i*512) + 512));
        }

        ArrayList<ArrayList<String>> words = new ArrayList<ArrayList<String>>();
        for(int i=0; i<chunks.size();i++){
            ArrayList<String> temp = new ArrayList<String>();
            String tempStr = chunks.get(i);

            for(int j=0;j<16;j++){
                temp.add(tempStr.substring(j*32, (j*32) +32));
            }
            words.add(temp);
        }

        //Use XOR to extend each chunk to have 80 32-bit words
        int size = chunks.size();
        for(int i=0; i<size;i++){
            for(int j=16;j<80;j++){
                //calculate word using XOR on long values
                long t1 = Long.parseLong(words.get(i).get(j-3), 2);
                long t2 = Long.parseLong(words.get(i).get(j-8), 2);
                long t3 = Long.parseLong(words.get(i).get(j-14), 2);
                long t4 = Long.parseLong(words.get(i).get(j-16), 2);

                long t = t1 ^ t2 ^ t3 ^ t4;//new word to append

                String toApp = Long.toBinaryString(t);//convert to string
                while(toApp.length()<32){
                    toApp="0"+toApp;
                }
                if(toApp.length()!=32){
                    System.out.println("Error");
                    System.out.println(toApp.length());
                }
                ArrayList<String> temp = words.get(i);
                temp.add(toApp);
                words.add(i, temp);
            }
        }

        return words;
    }

    private static String hashF2(String s){
        String ret = null;
        
        if ((s.length() > 64) || (s.length() < 1)) { // String does not have required length
            ret = null;
        }else{
            /*
            The following is an implementation of SHA-1 hashing algorithm that follows the pseudo code from:
            https://en.wikipedia.org/wiki/SHA-1
            It returns a 160-bit hexadecimal hash (the size is 40)
            */

            //default values
            long h0 = 0x67452301;
            long h1 = 0xEFCDAB89;
            long h2 = 0x98BADCFE;
            long h3 = 0x10325476;
            long h4 = 0xC3D2E1F0;
            ArrayList<ArrayList<String>> words = preprocessing(s);

            //loop over each chunk and reassign initialised variables h0 -> h4 using bitwise operations
            for(int i=0; i<words.size();i++){
                long a = h0;
                long b = h1;
                long c = h2;
                long d = h3;
                long e = h4;

                long f = 0x0;
                long k = 0x0;

                //loop over each word and calculate f and k correspondingly
                for(int j=0;j<80;j++){
                    if(j>= 0 && j <= 19){
                        f = (b & c) | ((~ b) & d);
                        k = 0x5A827999;
                    }
                    else if( j>= 20 && j<= 39){
                        f = b ^ c ^ d;
                        k = 0x6ED9EBA1;
                    }
                    else if(j>=40 && j<=59){
                        f = (b & c) | (b & d) | (c & d); 
                        k = 0x8F1BBCDC;
                    }
                    else if(j>=60 && j<= 79){
                        f = b ^ c ^ d;
                        k = 0xCA62C1D6;
                    }

                    //left shift a by 5 bits then add to f, e, k, and the jth word of the ith chunk
                    long temp = Long.rotateLeft(a, 5) + f + e + k + Long.parseLong(words.get(i).get(j), 2);
                    e = d;
                    d = c;
                    c = Long.rotateLeft(b, 30); 
                    b = a;
                    a = temp;
            
                }
                //after each chunk reassign h0 to h4
                h0 = h0 + a;
                h1 = h1 + b;
                h2 = h2 + c;
                h3 = h3 + d;
                h4 = h4 + e;
            }
            /*
            turn h values to a hash string
            */
            
            //get hex strings from each h
            String h0S = Long.toHexString(h0);
            String h1S = Long.toHexString(h1);
            String h2S = Long.toHexString(h2);
            String h3S = Long.toHexString(h3);
            String h4S = Long.toHexString(h4);
            
            System.out.println(h0S);
            System.out.println(h1S);
            System.out.println(h2S);
            System.out.println(h3S);
            System.out.println(h4S);
            System.out.println(" ");

            while(h0S.length() < 40) {
                StringBuilder h0L = new StringBuilder(h0S);
                h0L.insert(0,0);
                h0S = h0L.toString();
            }
            while(h1S.length() < 40) {
                StringBuilder h1L = new StringBuilder(h1S);
                h1L.insert(0,0);
                h1S = h1L.toString();
            }
            while(h2S.length() < 40) {
                StringBuilder h2L = new StringBuilder(h2S);
                h2L.insert(0,0);
                h2S = h2L.toString();
            }
            while(h3S.length() < 40) {
                StringBuilder h3L = new StringBuilder(h3S);
                h3L.insert(0,0);
                h3S = h3L.toString();
            }
            while(h4S.length() < 40) {
                StringBuilder h4L = new StringBuilder(h4S);
                h4L.insert(0,0);
                h4S = h4L.toString();
            }
         
            //left rotate h0 -> h3 according to wikipedia pseudocode
            //note that the pseudocode distances are divided by 4 since this is rotating hexadecimal values not binary values
            h0S = h0S.substring(32) + h0S.substring(0, 32);
            h1S = h1S.substring(24) + h1S.substring(0, 24);
            h2S = h2S.substring(16) + h2S.substring(0, 16);
            h3S = h3S.substring(8) + h3S.substring(0, 8);
  
            //convert to BigInteger to be able to store in a format that can be ORed easily
            BigInteger b0 = new BigInteger(h0S, 16);
            BigInteger b1 = new BigInteger(h1S, 16);
            BigInteger b2 = new BigInteger(h2S, 16);
            BigInteger b3 = new BigInteger(h3S, 16);
            BigInteger b4 = new BigInteger(h4S, 16);

            //OR all values to create the final hash value
            BigInteger hh = b0.or(b1).or(b2).or(b3).or(b4);
            ret = hh.toString(16);//return as string

        }
        return ret;
    }
私有静态ArrayList预处理(字符串s){
字符串二进制_message=“”;
对于(int i=0;i