【问题标题】:How to hash some string with sha256 in Java?如何在 Java 中使用 sha256 散列一些字符串?
【发布时间】:2011-07-28 17:40:28
【问题描述】:

如何在 Java 中使用 sha256 散列一些字符串?

【问题讨论】:

标签: java cryptography sha256 cryptographic-hash-function


【解决方案1】:

SHA-256 不是一种“编码”——它是一种单向哈希。

您基本上会将字符串转换为字节(例如使用text.getBytes(StandardCharsets.UTF_8)),然后对字节进行哈希处理。请注意,散列的结果是任意二进制数据,如果你想用字符串表示它,你应该use base64或十六进制... 不要 em> 尝试使用String(byte[], String) 构造函数。

例如

MessageDigest digest = MessageDigest.getInstance("SHA-256");
byte[] hash = digest.digest(text.getBytes(StandardCharsets.UTF_8));

【讨论】:

  • "SHA-256 is not an encoding" 绝对正确,但我必须说我更喜欢当前问题的标题,而不是“如何使用 sha 加密”(很多人似乎认为这是加密)。也许我们应该将其视为编码而不是与密码学有关,因为在实践中这更接近于它的使用方式。
  • @Luc:嗯,这是一个加密哈希,所以我认为说它确实与密码学有关......加密和密码学不是'可互换...
  • 注意:在 Java 7+ 中使用 StandardCharsets.UTF_8 而不是 "UTF-8" 文字是个好主意:一个检查异常不用担心。
  • 为什么在处理哈希结果时要避免使用 String(byte[], String) 构造函数?
  • @IsaacvanBakel:因为散列不是编码文本。它是任意二进制数据。
【解决方案2】:

这是一个返回String的方法:

public static String sha256(final String data) {
    try {
        final byte[] hash = MessageDigest.getInstance("SHA-256").digest(data.getBytes(StandardCharsets.UTF_8));
        final StringBuilder hashStr = new StringBuilder(hash.length);

        for (byte hashByte : hash)
            hashStr.append(Integer.toHexString(255 & hashByte));

        return hashStr.toString();
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
        return null;
    }
}

【讨论】:

    【解决方案3】:

    完整的示例哈希到字符串作为另一个字符串。

    public static String sha256(final String base) {
        try{
            final MessageDigest digest = MessageDigest.getInstance("SHA-256");
            final byte[] hash = digest.digest(base.getBytes("UTF-8"));
            final StringBuilder hexString = new StringBuilder();
            for (int i = 0; i < hash.length; i++) {
                final String hex = Integer.toHexString(0xff & hash[i]);
                if(hex.length() == 1) 
                  hexString.append('0');
                hexString.append(hex);
            }
            return hexString.toString();
        } catch(Exception ex){
           throw new RuntimeException(ex);
        }
    }
    

    【讨论】:

    • 要将 Jon 的结果编码为十六进制,请考虑使用现有的库,如 apache commons,而不是自己滚动。
    • 为什么选择 StringBuffer? (不是字符串生成器)?也许最好设置 stringbuilder 的默认大小?
    • @Leigh:有些人不想添加整个 lib 依赖项只是因为他们需要它的单个函数,所以滚动你自己的有时是个好主意。
    • @Chris - 是的。这就是为什么我说“考虑”使用它;-) 现有的库可以增加批量。另一方面,它们通常比自制代码经过更高的测试,当然也可以节省时间。但没有适合所有人的万能答案。
    • 你也可以从库中读取源代码并复制它的代码!
    【解决方案4】:

    这是我用于散列的内容:

    String pass = "password";
    
    MessageDigest messageDigest = MessageDigest.getInstance("SHA-256");
    byte hashBytes[] = messageDigest.digest(pass.getBytes(StandardCharsets.UTF_8));
    BigInteger noHash = new BigInteger(1, hashBytes);
    String hashStr = noHash.toString(16);
    

    输出:5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8

    【讨论】:

      【解决方案5】:

      在 Java 8 中

      import java.nio.charset.StandardCharsets;
      import java.security.MessageDigest;
      import java.security.NoSuchAlgorithmException;
      import java.util.Scanner;
      import javax.xml.bind.DatatypeConverter;
      
      
      Scanner scanner = new Scanner(System.in);
      String password = scanner.nextLine();
      scanner.close();
      
      MessageDigest digest = null;
      try {
          digest = MessageDigest.getInstance("SHA-256");
      } catch (NoSuchAlgorithmException e) {
          // TODO Auto-generated catch block
          e.printStackTrace();
      }
      byte[] hash = digest.digest(password.getBytes(StandardCharsets.UTF_8));
      String encoded = DatatypeConverter.printHexBinary(hash);        
      System.out.println(encoded.toLowerCase());
      

      【讨论】:

      • 你为什么会有这样的try/catch?
      【解决方案6】:

      在 Java 中,MessageDigest 类用于计算加密哈希值。该类提供加密哈希函数(MD5SHA-1SHA-256)来查找文本的哈希值。

      使用 SHA-256 算法的代码示例。

      public void printHash(String str) throws NoSuchAlgorithmException {
      
      MessageDigest md=MessageDigest.getInstance("SHA-256");
      
      byte[] sha256=md.digest(str.getBytes(StandardCharsets.UTF_8));
      
         for(byte b : sha256){
      
            System.out.printf("%02x",b);
      
        }
      }
      

      【讨论】:

        【解决方案7】:
        private static String getMessageDigest(String message, String algorithm) {
         MessageDigest digest;
         try {
          digest = MessageDigest.getInstance(algorithm);
          byte data[] = digest.digest(message.getBytes("UTF-8"));
          return convertByteArrayToHexString(data);
         } catch (NoSuchAlgorithmException | UnsupportedEncodingException e) {
          // TODO Auto-generated catch block
          e.printStackTrace();
         }
         return null;
        }
        

        您可以使用不同的算法调用上述方法,如下所示。

        getMessageDigest(message, "MD5");
        getMessageDigest(message, "SHA-256");
        getMessageDigest(message, "SHA-1");
        

        您可以参考此link 以获取完整的申请。

        【讨论】:

          【解决方案8】:

          这是我使用 Kotlin 的方法:

          private fun getHashFromEmailString(email : String) : String{
              val charset = Charsets.UTF_8
              val byteArray = email.toByteArray(charset)
              val digest = MessageDigest.getInstance("SHA-256")
              val hash = digest.digest(byteArray)
          
              return hash.fold("", { str, it -> str + "%02x".format(it)})
          }
          

          【讨论】:

          • 您好,我刚刚尝试了您的代码,因为我需要在 Android Studio 中对密码进行哈希处理,您的代码返回如下内容:[B@188363e,而不是加密密码。另外,每次调用这个函数似乎都不一样。
          • 已修复,您忘记了 return hash.fold("", { str, it -&gt; str + "%02x".format(it)}) 返回加密密码而不是对象本身。
          • 是的,你是对的,让我用你的修复更新答案。谢谢你:)
          【解决方案9】:
          import java.security.MessageDigest;
          
          public class CodeSnippets {
          
           public static String getSha256(String value) {
              try{
                  MessageDigest md = MessageDigest.getInstance("SHA-256");
                  md.update(value.getBytes());
                  return bytesToHex(md.digest());
              } catch(Exception ex){
                  throw new RuntimeException(ex);
              }
           }
           private static String bytesToHex(byte[] bytes) {
              StringBuffer result = new StringBuffer();
              for (byte b : bytes) result.append(Integer.toString((b & 0xff) + 0x100, 16).substring(1));
              return result.toString();
           }
          }
          

          【讨论】:

          • 0xff 对字节值进行按位 &-ing 的意义何在?它什么也没有产生,不是吗?
          • @yktoo :它将其转换为正整数(不幸的是,字节用 Java 签名)stackoverflow.com/questions/11380062/…
          • StringBuffer 可以替换为 StringBuilder
          【解决方案10】:
          String hashWith256(String textToHash) {
              MessageDigest digest = MessageDigest.getInstance("SHA-256");
              byte[] byteOfTextToHash = textToHash.getBytes(StandardCharsets.UTF_8);
              byte[] hashedByetArray = digest.digest(byteOfTextToHash);
              String encoded = Base64.getEncoder().encodeToString(hashedByetArray);
              return encoded;
          }
          

          【讨论】:

            【解决方案11】:

            这是一种将摘要转换为十六进制字符串的更高效的方法:

            private static final char[] hexArray = "0123456789abcdef".toCharArray();
            
            public static String getSHA256(String data) {
                StringBuilder sb = new StringBuilder();
                try {
                    MessageDigest md = MessageDigest.getInstance("SHA-256");
                    md.update(data.getBytes());
                    byte[] byteData = md.digest();
                    sb.append(bytesToHex(byteData);
                } catch(Exception e) {
                    e.printStackTrace();
                }
                return sb.toString();
            }
            
            private static String bytesToHex(byte[] bytes) {
                char[] hexChars = new char[bytes.length * 2];
                for ( int j = 0; j < bytes.length; j++ ) {
                    int v = bytes[j] & 0xFF;
                    hexChars[j * 2] = hexArray[v >>> 4];
                    hexChars[j * 2 + 1] = hexArray[v & 0x0F];
                }
                return String.valueOf(hexChars);
            }
            

            有没有人知道 Java 中更快的方法?

            【讨论】:

              【解决方案12】:

              如果您使用的是 Java 8,则可以通过以下方式对 byte[] 进行编码

              MessageDigest digest = MessageDigest.getInstance("SHA-256");
              byte[] hash = digest.digest(text.getBytes(StandardCharsets.UTF_8));
              String encoded = Base64.getEncoder().encodeToString(hash);
              

              【讨论】:

              • 这种方式对我来说很方便。但是,您应该使用以下 Base64.encodeToString(hash, Base64.DEFAULT);
              • @MotassemJalal Base64.DEFAULT 在最新版本的 Java8 中不可用,我目前使用的是 jdk1.8.0_144,您能告诉我您是如何创建它的吗?
              • @rajadilipkolli 我认为这是 Android 实现:developer.android.com/reference/android/util/Base64
              • 出于某种原因,我得到了错误的结果。示例:对于“测试”的输入,我得到了 n4bQgYhMfWWaL+qgxVrQFaO/TxsrC4Is0V1sFbDwCgg= 而不是 9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08 。怎么会?
              • 这是一种方法,但不是通用标准。 @android 开发者,这就是为什么您在这里看到的价值与您在其他实现中看到的不同。
              【解决方案13】:

              您可以通过以下方式使用 MessageDigest:

              public static String getSHA256(String data){
                  StringBuffer sb = new StringBuffer();
                  try{
                      MessageDigest md = MessageDigest.getInstance("SHA-256");
                      md.update(data.getBytes());
                      byte byteData[] = md.digest();
              
                      for (int i = 0; i < byteData.length; i++) {
                       sb.append(Integer.toString((byteData[i] & 0xff) + 0x100, 16).substring(1));
                      }
                  } catch(Exception e){
                      e.printStackTrace();
                  }
                  return sb.toString();
              }
              

              【讨论】:

                【解决方案14】:

                我通过DigestUtils 跟踪Apache 代码,sha256 似乎默认回到java.security.MessageDigest 进行计算。 Apache 没有实现独立的sha256 解决方案。我正在寻找一个独立的实现来与java.security 库进行比较。仅供参考。

                【讨论】:

                  【解决方案15】:

                  另一种选择是Guava,它具有易于使用的Hashing 实用程序套件。例如,要使用 SHA256 作为十六进制字符串散列字符串,您只需执行以下操作:

                  final String hashed = Hashing.sha256()
                          .hashString("your input", StandardCharsets.UTF_8)
                          .toString();
                  

                  【讨论】:

                  • 请注意——自第 11 版引入以来,它在第 30 版中仍标记为 @Beta。
                  【解决方案16】:

                  我认为最简单的解决方案是使用Apache Common Codec

                  String sha256hex = org.apache.commons.codec.digest.DigestUtils.sha256Hex(stringText);   
                  

                  【讨论】:

                  • 最佳答案,易于使用,干净。谢谢!
                  猜你喜欢
                  • 2020-05-03
                  • 1970-01-01
                  • 2020-11-21
                  • 2018-06-12
                  • 2019-10-04
                  • 1970-01-01
                  • 2023-03-31
                  • 1970-01-01
                  • 2022-01-16
                  相关资源
                  最近更新 更多