如何在Android中将SHA1哈希为字符串?


72

在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上也需要同样的软件,但找不到如何做。我一直在寻找这样的例子:在Android上进行SHA1加密? 但这并不能为我带来与iPhone相同的结果。谁能指出我正确的方向?

Answers:


157

您不需要这个。您可以使用简单的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()做错了。您的代码运行正常。
马丁

太好了..非常感谢
彼得

23
为什么用iso-8559-1编码而不是UTF-8?除非需要与某些现有应用程序兼容,否则这些都是使用此类传统编码的理由。
CodesInChaos

8
如下所述,text.length()是不正确的,因为它不会返回字节数。您需要使用getBytes返回的数组的长度。而且,是的,它实际上可能不应该是iso-8859。
Jesse Rusak

Android上的“ md”是否可以为null?
Android开发者

37

一种更简单的SHA-1方法:(根据评论者的建议进行了更新,还使用了效率更高的byte-> string算法

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 );
}

2
如果sha1字符串应该以0开头,则将0排除在外。因此,在某些情况下,此方法返回错误的sha-1编码字符串。
梅尔文(Melvin)2012年

2
警告:如果您想对'1122'进行散列,则
不起作用

正确!更新了答案以解决此问题。感谢您抓住这个家伙。
亚当

1
由于代码是当前代码,因此只返回原始字符串的十六进制版本,不进行哈希处理。需要在某个地方调用digest.digest()。
eselk

4
使用默认的encoding(somestring.GetBytes())将为您提供平台相关的哈希值。不太好。使用固定编码,最好使用UTF-8。
CodesInChaos

31

如果您可以摆脱使用Guava的麻烦,那么这是迄今为止最简单的方法,而且您不必重新发明轮子:

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

然后,您可以采取的散列值,并把它作为byte[],作为int或作为long

不需尝试即可包装,无需恶作剧。而且,如果您决定使用SHA-1以外的其他软件,那么Guava还支持sha256,sha 512,还有一些我从未听说过的语言,例如adler32和murmur3。


3
我真的很喜欢这个答案,因为它非常适合Android,并且不需要我仔细检查SO代码是否存在安全漏洞:p
Muz,2016年

19
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();

3
注意:如果要避免大写,请使用“%02x”。
JM Lord

16

完全基于@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;
    }
}

1
正如其他答案所建议的那样,您应该clearString.getBytes("UTF-8")习惯安全起见。
Ridcully

我将此代码实现到我的Android应用中,并且运行良好。感谢分享。
卡洛斯·埃斯皮诺萨


2

您要寻找的方法并非特定于Android,而是通常针对Java。您正在寻找MessageDigestimport java.security.MessageDigest)。

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

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

太好了,我要分享我的完整实现:stackoverflow.com/a/33260623/423171
cprcrack

0

这是获取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/


-19
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]);

2
重点不是显示如何格式化哈希,而是重点在于如何创建哈希。
Triang3l 2013年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.