【问题标题】:How to SHA1 hash a string in Android?如何在 Android 中对字符串进行 SHA1 哈希处理?
【发布时间】:2011-08-24 06:02:44
【问题描述】:

在 Objective C 中,我一直在使用以下代码来散列字符串:

-(NSString *) sha1:(NSString*)stringToHash {    
    const char *cStr = [stringToHash UTF8String];
    unsigned char result[20];
    CC_SHA1( cStr, strlen(cStr), result );
    return [NSString stringWithFormat:@"%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
        result[0], result[1], result[2], result[3], 
        result[4], result[5], result[6], result[7],
        result[8], result[9], result[10], result[11],
        result[12], result[13], result[14], result[15],
        result[16], result[17], result[18], result[19]
        ];  
}

现在我需要为 Android 提供相同的功能,但不知道该怎么做。我一直在寻找这个例子:Make SHA1 encryption on Android? 但这并没有给我与 iPhone 相同的结果。谁能指出我正确的方向?

【问题讨论】:

    标签: android hash sha1


    【解决方案1】:

    在 Kotlin 中,这可以缩短并放在一行中:

    MessageDigest.getInstance("SHA-1").digest(theString.toByteArray()).joinToString("") { "%02x".format(it) }
    

    【讨论】:

      【解决方案2】:

      这里是获取 SHA 加密字符串的 Kotlin 版本。

      import java.security.MessageDigest
      
      object HashUtils {
          fun sha512(input: String) = hashString("SHA-512", input)
      
          fun sha256(input: String) = hashString("SHA-256", input)
      
          fun sha1(input: String) = hashString("SHA-1", input)
      
          /**
           * Supported algorithms on Android:
           *
           * Algorithm    Supported API Levels
           * MD5          1+
           * SHA-1        1+
           * SHA-224      1-8,22+
           * SHA-256      1+
           * SHA-384      1+
           * SHA-512      1+
           */
          private fun hashString(type: String, input: String): String {
              val HEX_CHARS = "0123456789ABCDEF"
              val bytes = MessageDigest
                      .getInstance(type)
                      .digest(input.toByteArray())
              val result = StringBuilder(bytes.size * 2)
      
              bytes.forEach {
                  val i = it.toInt()
                  result.append(HEX_CHARS[i shr 4 and 0x0f])
                  result.append(HEX_CHARS[i and 0x0f])
              }
      
              return result.toString()
          }
      }
      

      原贴在这里:https://www.samclarke.com/kotlin-hash-strings/

      【讨论】:

        【解决方案3】:
        final MessageDigest digest = MessageDigest.getInstance("SHA-1");
        result = digest.digest(stringToHash.getBytes("UTF-8"));
        
        // Another way to construct HEX, my previous post was only the method like your solution
        StringBuilder sb = new StringBuilder();
        
        for (byte b : result) // This is your byte[] result..
        {
            sb.append(String.format("%02X", b));
        }
        
        String messageDigest = sb.toString();
        

        【讨论】:

        • 注意:如果要避免大写,请使用“%02x”。
        【解决方案4】:

        您不需要为此使用 andorid。你可以用简单的java来做。

        您是否尝试过一个简单的 java 示例,看看它是否返回正确的 sha1。

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

        还分享您期望的 sha1 应该是什么。也许 ObjectC 做错了。

        【讨论】:

        • 感谢您的回答!我使用的 convertToHex() 做错了。您的代码运行良好。
        • 太棒了.. 非常感谢
        • 为什么使用 iso-8559-1 编码而不是 UTF-8?除非您需要与某些现有应用程序兼容,否则几乎没有理由使用此类遗留编码。
        • 正如下面有人提到的, text.length() 不正确,因为它不会返回字节数。您需要使用 getBytes 返回的数组长度。而且,是的,它真的可能不应该是 iso-8859。
        • Android 上的“md”可以为空吗?
        【解决方案5】:

        完全基于@Whymarrh 的回答,这是我的实现,经过测试并且工作正常,没有依赖关系:

        public static String getSha1Hex(String clearString)
        {
            try
            {
                MessageDigest messageDigest = MessageDigest.getInstance("SHA-1");
                messageDigest.update(clearString.getBytes("UTF-8"));
                byte[] bytes = messageDigest.digest();
                StringBuilder buffer = new StringBuilder();
                for (byte b : bytes)
                {
                    buffer.append(Integer.toString((b & 0xff) + 0x100, 16).substring(1));
                }
                return buffer.toString();
            }
            catch (Exception ignored)
            {
                ignored.printStackTrace();
                return null;
            }
        }
        

        【讨论】:

        • 按照其他答案的建议,为了安全起见,您应该使用clearString.getBytes("UTF-8")
        • 我将此代码实现到我的 Android 应用程序中并且运行良好。感谢分享。
        【解决方案6】:

        更简单的 SHA-1 方法:(根据评论者的建议进行了更新,还使用了更高效的字节->字符串算法

        String sha1Hash( String toHash )
        {
            String hash = null;
            try
            {
                MessageDigest digest = MessageDigest.getInstance( "SHA-1" );
                byte[] bytes = toHash.getBytes("UTF-8");
                digest.update(bytes, 0, bytes.length);
                bytes = digest.digest();
        
                // This is ~55x faster than looping and String.formating()
                hash = bytesToHex( bytes );
            }
            catch( NoSuchAlgorithmException e )
            {
                e.printStackTrace();
            }
            catch( UnsupportedEncodingException e )
            {
                e.printStackTrace();
            }
            return hash;
        }
        
        // http://stackoverflow.com/questions/9655181/convert-from-byte-array-to-hex-string-in-java
        final protected static char[] hexArray = "0123456789ABCDEF".toCharArray();
        public 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 new String( hexChars );
        }
        

        【讨论】:

        • 如果 sha1 字符串应该以 0 开头,那么 0 会被忽略。所以这个方法在某些情况下会返回错误的 sha-1 编码字符串。
        • 警告:如果你想散列 '1122' 则不起作用,它以 0 开头
        • 正确!更新了解决此问题的答案。感谢您抓住这些人。
        • 目前的代码只返回原始字符串的十六进制版本,没有散列。需要在某处调用 digest.digest()。
        • 使用默认编码(somestring.GetBytes()) 将为您提供平台相关的哈希值。不是很好。使用固定编码,最好是 UTF-8。
        【解决方案7】:

        如果您可以摆脱using Guava it is by far the simplest way to do it,并且您不必重新发明轮子:

        final HashCode hashCode = Hashing.sha1().hashString(yourValue, Charset.defaultCharset());
        

        然后您可以获取哈希值并将其作为byte[]intlong 获取。

        没有尝试捕获,没有恶作剧。如果你决定要使用 SHA-1 以外的东西,Guava 还支持 sha256、sha 512 以及一些我从未听说过的东西,比如 adler32 和 murmur3。

        【讨论】:

        • 我真的很喜欢这个答案,因为它非常适合 Android,并且不需要我仔细检查 SO 代码是否存在安全漏洞:p
        【解决方案8】:

        Android 带有 Apache 的 Commons Codec - 或者您将其添加为依赖项。然后做:

        String myHexHash = DigestUtils.shaHex(myFancyInput);
        

        这是您在 Android 4 中默认使用的旧的已弃用方法。新版本的 DigestUtils 带来了各种风格的 shaHex() 方法,例如 sha256Hex(),并且还使用不同的参数类型重载了这些方法。

        http://commons.apache.org/proper/commons-codec//javadocs/api-release/org/apache/commons/codec/digest/DigestUtils.html

        【讨论】:

          【解决方案9】:

          您正在寻找的方法不是特定于 Android,而是一般的 Java。您正在寻找MessageDigest (import java.security.MessageDigest)。

          sha512(String s) 方法的实现可以看到 here,SHA-1 哈希的更改将第 71 行更改为:

          MessageDigest md = MessageDigest.getInstance("SHA-1");
          

          【讨论】:

          【解决方案10】:
          String.format("%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", result[0], result[1], result[2], result[3], 
              result[4], result[5], result[6], result[7],
              result[8], result[9], result[10], result[11],
              result[12], result[13], result[14], result[15],
              result[16], result[17], result[18], result[19]);
          

          【讨论】:

          • 重点不是展示如何格式化散列,重点是展示如何创建它。
          猜你喜欢
          • 2011-04-25
          • 1970-01-01
          • 2021-09-19
          • 2018-11-08
          • 2014-11-03
          • 1970-01-01
          • 2014-05-13
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多