【问题标题】:Compute SHA-1 of byte array计算字节数组的 SHA-1
【发布时间】:2010-12-03 16:23:22
【问题描述】:

我正在寻找一种以 Java 字节数组作为消息获取 SHA-1 校验和的方法。

我应该使用第三方工具还是 JVM 内置的东西可以提供帮助?

【问题讨论】:

  • 我在寻找同样的东西。一种在 Java 中计算 SHA1 的方法。我得到什么?两个答案。有很多“这是错误的”,“这太可怕了”。然而,写这些 cmets 的人并没有写出一个“好”的答案。

标签: java sha1


【解决方案1】:

怎么样:

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Formatter;

public static String SHAsum(byte[] convertme) throws NoSuchAlgorithmException{
    MessageDigest md = MessageDigest.getInstance("SHA-1"); 
    return byteArray2Hex(md.digest(convertme));
}

private static String byteArray2Hex(final byte[] hash) {
    Formatter formatter = new Formatter();
    for (byte b : hash) {
        formatter.format("%02x", b);
    }
    return formatter.toString();
}

【讨论】:

  • 我只是在寻找计算 sha1 的方法——格式无关紧要
  • @PascalThivent 但是另一个程序员可能会停下来使用这个答案,包括错误(这毕竟部分是关于 SO 的)。散列本身有足够的模糊性(像“通过 sha-1 散列这些串联的字符串来计算这个签名”这样的文档,没有提到如何编码输入字符和字符串化散列输出,已经很常见了)。
  • 这甚至没有正确编译。我不明白两年前拥有 152k 代表的用户是如何写出这样的答案的,直到现在也没有人编辑它。
  • @jarnbjo 感谢您指出潜在问题。但是为什么我看不到你的帖子“有”正确答案呢?它可能不会被接受为正确答案,但它的投票率可能会比目前的 9 票多得多。
  • 我相信提到答案错误的评论不再相关。答案已编辑,转换为十六进制字符串看起来不错。
【解决方案2】:

您可以自己做,但我建议使用已被证明有效的库,例如 Commons CodecDigestUtils 类有几种计算哈希的方法。

【讨论】:

    【解决方案3】:

    这是我们用来转换为 SHA-1 的代码的 sn-p,但需要 String 而不是 Byte[],请参阅此 javadoc 了解更多信息

            import java.io.UnsupportedEncodingException;
            import java.security.MessageDigest;
            import java.security.NoSuchAlgorithmException;
    
            public class DoSHA1 {
    
                private static String convToHex(byte[] data) {
                    StringBuilder buf = new StringBuilder();
                    for (int i = 0; i < data.length; i++) {
                        int halfbyte = (data[i] >>> 4) & 0x0F;
                        int two_halfs = 0;
                        do {
                            if ((0 <= halfbyte) && (halfbyte <= 9))
                                buf.append((char) ('0' + halfbyte));
                            else
                                buf.append((char) ('a' + (halfbyte - 10)));
                            halfbyte = data[i] & 0x0F;
                        } while(two_halfs++ < 1);
                    }
                    return buf.toString();
                }
    
                public static String SHA1(String text) throws NoSuchAlgorithmException,
    UnsupportedEncodingException  {
                MessageDigest md = MessageDigest.getInstance("SHA-1");
                byte[] sha1hash = new byte[40];
                md.update(text.getBytes("iso-8859-1"), 0, text.length());
                sha1hash = md.digest();
                return convToHex(sha1hash);
                }
            }
    

    【讨论】:

    • 如果它对你来说足够快,你也可以使用 String.format("%02x", b) 将字节转换为十六进制字符串。
    • 你分配一个新的40字节数组的那一行是没用的;数组对象来自 md.digest() 调用。当您将该方法的返回值分配给 sha1hash 时,您会擦除您创建的 40 字节空数组。
    • 此外,SHA-1 摘要是 20 个字节,而不是 40 个字节。
    【解决方案4】:

    从CommonCodec DigestUtils 实现Digest计算后的Hex覆盖如前所示:

    MessageDigest md = MessageDigest.getInstance("SHA-1"); 
    return byteArray2Hex(md.digest(convertme));
    

    应该是http://commons.apache.org/codec/apidocs/src-html/org/apache/commons/codec/binary/Hex.html#line.129

    private static final char[] DIGITS_LOWER = 
       {'0', '1', '2', '3', '4', '5', '6', '7',
        '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
    
    private static final char[] DIGITS_UPPER = 
       {'0', '1', '2', '3', '4', '5', '6', '7',
        '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
    
    protected static char[] encodeHex(byte[] data, char[] toDigits) {
        int l = data.length;
        char[] out = new char[l << 1];
        // two characters form the hex value.
        for (int i = 0, j = 0; i < l; i++) {
            out[j++] = toDigits[(0xF0 & data[i]) >>> 4];
            out[j++] = toDigits[0x0F & data[i]];
        }
        return out;
    }
    
    protected static int toDigit(char ch, int index) throws DecoderException {
        int digit = Character.digit(ch, 16);
        if (digit == -1) {
            throw new DecoderException(
                        "Illegal hexadecimal character " 
                + ch + " at index " + index);
        }
        return digit;
    }
    
    public static String exampleSha1(String convertme){
        MessageDigest md = MessageDigest.getInstance("SHA-1"); 
        byte[] encodeHex = md.digest(convertme));
        return new String(encodeHex);
    }
    

    【讨论】:

      【解决方案5】:

      ...另一种选择是使用 Spring:

      <bean id="passwordEncoder" class="org.springframework.security.authentication.encoding.ShaPasswordEncoder">
           <constructor-arg value="256"/>
       </bean>
      

      阅读更多here

      HTH

      【讨论】:

      • 它的开销惊人 :))
      【解决方案6】:

      我只是用它来计算 dex 文件内的哈希和,并将其与保存在 dex 文件中的值进行比较。

      我知道这段代码没有很好的风格,但它更多的是 PoC,只需要一些时间不紧迫的研究。有人可以用吗!

      class CheckDex{
      public boolean checkSHA1(File f) throws IOException, NoSuchAlgorithmException{
          RandomAccessFile raf = new RandomAccessFile(f, "r");
          byte[] sig = new byte[20];
          raf.seek(0xC);
          for(int i = 0; i < 20; i++){
              sig[i] = (byte) raf.readUnsignedByte();
          }
      
          MessageDigest md = MessageDigest.getInstance("SHA-1"); 
      
          byte[] code = new byte[(int) (raf.length()-32)];
          for(int i = 0; i < code.length; i++){
              code[i] = (byte) raf.readUnsignedByte();
          }
          byte[] comsig = md.digest(code);
      
          raf.close();
          return Arrays.equals(sig,comsig);
      }
      }
      

      【讨论】:

        【解决方案7】:

        如何使用这个:

        公共类 sha1Calculate {

            public static void main(String[] args)throws Exception
            {
                 File file = new File("D:\\Android Links.txt");
                String outputTxt= "";
                String hashcode = null;
        
                try {
        
                    FileInputStream input = new FileInputStream(file);
        
                    ByteArrayOutputStream output = new ByteArrayOutputStream ();
                    byte [] buffer = new byte [65536];
                    int l;
        
                    while ((l = input.read (buffer)) > 0)
                        output.write (buffer, 0, l);
        
                    input.close ();
                    output.close ();
        
                    byte [] data = output.toByteArray ();
        
        
                        MessageDigest digest = MessageDigest.getInstance( "SHA-1" ); 
        
                    byte[] bytes = data;
        
                    digest.update(bytes, 0, bytes.length);
                    bytes = digest.digest();
        
                    StringBuilder sb = new StringBuilder();
        
                    for( byte b : bytes )
                    {
                        sb.append( String.format("%02X", b) );
                    }
        
                        System.out.println("Digest(in hex format):: " + sb.toString());
        
        
                }catch (FileNotFoundException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (NoSuchAlgorithmException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        
            }
        
        }
        

        【讨论】:

          【解决方案8】:

          以下代码将给定的byte[] 转换为 SHA-1 哈希的String

          import java.math.BigInteger;
          import java.security.MessageDigest;
          import java.security.NoSuchAlgorithmException;
          
          public static String hash(byte data[]) throws NoSuchAlgorithmException
          {
             MessageDigest digest;
             BigInteger big;
             String result;
             byte hash[];
          
             digest = MessageDigest.getInstance("SHA-1"); 
             hash   = digest.digest(data);
             big    = new BigInteger(1, hash);
             result = big.toString(16);
          
             return result;
          }
          

          注意:前导零将被修剪。因此,这可能会或可能不会工作,具体取决于您的用例。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-08-24
            • 1970-01-01
            • 2018-11-08
            • 2019-12-04
            • 1970-01-01
            • 2011-10-14
            相关资源
            最近更新 更多