如何在 Android 中 SHA1散列一个字符串?

在 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 上进行 SHA1加密? 但是这并不能给我带来和 iPhone 一样的结果。有人能给我指出正确的方向吗?

112995 次浏览

你不需要 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应该是什么。

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

更简单的 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 );
}

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

可以看到 sha512(String s)方法的实现 给你,SHA-1散列的更改将更改第71行为:

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

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

如果你能摆脱 用番石榴是目前为止最简单的方法,你就不必重新发明轮子:

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

然后,您可以获取散列值,并将其作为 byte[]intlong获取。

不要试探性的包装,不要恶作剧。如果你决定使用 SHA-1以外的东西,Guava 也支持 sha256,sha 512,还有一些我从未听说过的例子,比如 adler32和 murmur3。

完全基于@Whymarr 的回答,这是我的实现,测试和工作良好,没有依赖:

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

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

对于 Kotlin,这个问题可以缩短为一句话:

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

在 kotlin 上使用扩展函数来简化它:

/**
* Encrypt String to SHA1 format
*/
fun String.toSha1(): String {
return MessageDigest
.getInstance("SHA-1")
.digest(this.toByteArray())
.joinToString(separator = "", transform = { "%02x".format(it) })
}