Java的字符串SHA1

问题描述 投票:135回答:12

我试图做一个简单的字符串在Java SHA1转换器,这是我得到了什么?

public static String toSHA1(byte[] convertme) {
    MessageDigest md = null;
    try {
        md = MessageDigest.getInstance("SHA-1");
    }
    catch(NoSuchAlgorithmException e) {
        e.printStackTrace();
    } 
    return new String(md.digest(convertme));
}

当我将它传递toSHA1("password".getBytes()),我得到[�a�ɹ??�%l�3~��.我知道这可能是一个简单的编码修正像UTF-8,但也有人告诉我,我应该做的就是我想要的是5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8?还是我做这完全错了吗?

java string sha1
12个回答
174
投票

UPDATE 您可以使用Apache Commons Codec(版本1.7+)为你做这项工作。

DigestUtils.sha1Hex(stringToConvertToSHexRepresentation)

由于@Jon Onstott这一建议。


老回答 将您的字节数组十六进制字符串。 Real's How To tells you how

return byteArrayToHexString(md.digest(convertme))

和(从皇马复制如何)

public static String byteArrayToHexString(byte[] b) {
  String result = "";
  for (int i=0; i < b.length; i++) {
    result +=
          Integer.toString( ( b[i] & 0xff ) + 0x100, 16).substring( 1 );
  }
  return result;
}

顺便说一句,你可以使用的Base64获得更紧凑的表示。阿帕奇共享编解码器API 1.4,有这个好的工具带走所有的痛苦。 refer here


2
投票

消息摘要(哈希值)是字节[]在字节[]出

消息摘要被定义为采用一个原始字节数组,并返回原始字节数组的函数(又名byte[])。例如SHA-1 (Secure Hash Algorithm 1)具有160位或20字节的摘要大小。原始字节数组通常不能被理解为像character encodings UTF-8,因为在每一个订单不是每一个字节是一个法律是编码。所以,把它们转换成一个String

new String(md.digest(subject), StandardCharsets.UTF_8)

可能会产生一些非法序列或具有代码指针未定义Unicode映射:

[�a�ɹ??�%l�3~��.

Binary-to-text Encoding

对于binary-to-text编码被使用。随着哈希值,是最常用的一种是HEX encoding or Base16。基本上一个字节可以从0具有值到255(或-128127签名),其等效于0x00-0xFF的HEX表示。因此六角将加倍输出的所需长度,这意味着有20字节的输出将产生一个40字符长的十六进制字符串,例如:

2fd4e1c67a2d28fced849ee1bb76e7391b93eb12

注意,要使用十六进制编码它不是必需的。你也可以使用像base64。六角通常是优选的,因为它更容易可读人类和具有而不需要填充一个定义的输出长度。

你可以转换一个字节数组单独JDK功能为十六进制:

new BigInteger(1, token).toString(16)

但是,这种BigInteger会解释给定的字节数组作为数量,而不是作为一个字节的字符串注意。这意味着前导零将不会被输出,并且将得到的字符串可以是短于40个字符。

Using Libraries to Encode to HEX

现在,您可以copy and paste an untested byte-to-hex method from Stack Overflow或使用大量依赖像Guava

一展身手,以解决大多数字节相关问题我实现了一个工具来处理这些情况:bytes-java (Github)

要转换的消息摘要字节数组,你可以只是做

String hex = Bytes.wrap(md.digest(subject)).encodeHex();

或者你可以只使用内置的散列功能

String hex =  Bytes.from(subject).hashSha1().encodeHex();

1
投票

这不工作的原因是,当你调用String(md.digest(convertme)),你告诉Java的解释加密字节字符串序列。你需要的是字节转换为十六进制字符。


0
投票

转换字节数组十六进制字符串。

public static String toSHA1(byte[] convertme) {
    final char[] HEX_CHARS = "0123456789ABCDEF".toCharArray();
    MessageDigest md = null;
    try {
        md = MessageDigest.getInstance("SHA-1");
    }
    catch(NoSuchAlgorithmException e) {
        e.printStackTrace();
    }
    byte[] buf = md.digest(convertme);
    char[] chars = new char[2 * buf.length];
    for (int i = 0; i < buf.length; ++i) {
        chars[2 * i] = HEX_CHARS[(buf[i] & 0xF0) >>> 4];
        chars[2 * i + 1] = HEX_CHARS[buf[i] & 0x0F];
    }
    return new String(chars);
}

65
投票

这是我将字符串SHA1的解决方案。它运作良好,在我的Android应用程序:

private static String encryptPassword(String password)
{
    String sha1 = "";
    try
    {
        MessageDigest crypt = MessageDigest.getInstance("SHA-1");
        crypt.reset();
        crypt.update(password.getBytes("UTF-8"));
        sha1 = byteToHex(crypt.digest());
    }
    catch(NoSuchAlgorithmException e)
    {
        e.printStackTrace();
    }
    catch(UnsupportedEncodingException e)
    {
        e.printStackTrace();
    }
    return sha1;
}

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

53
投票

使用Guava Hashing class

Hashing.sha1().hashString( "password", Charsets.UTF_8 ).toString()

31
投票

SHA-1(和所有其他散列算法)返回二进制数据。这意味着,(在Java中),他们产生byte[]。这byte阵列不代表任何特定的字符,这意味着你不能简单地把它变成一个String像你这样。

如果你需要一个String,那么你必须格式化byte[]在可表示为String(否则,只是不停地围绕byte[])的方式。

表示任意byte[]的两种常用方法为可打印字符是BASE64或简单己字符串(即,表示由两个十六进制数字的每个byte)。它看起来像你想产生一个十六进制字符串。

还有另一个陷阱:如果你想获得一个Java String的SHA-1,那么你需要的是String转换到一个byte[](如SHA-1的输入是byte[]为好)。如果你只是使用myString.getBytes()为您呈现,那么它将使用平台默认的编码,因此将取决于你在运行环境中(例如,它可以返回根据您的操作系统的语言/区域设置不同的数据)。

更好的解决方案是指定要用于Stringbyte[]转换这样的编码:myString.getBytes("UTF-8")。选择UTF-8(或另一种编码可表示每Unicode字符)是这里的最安全的选择。


26
投票

这是一个简单的解决方案,可以将字符串转换为一个十六进制格式时,可以使用:

private static String encryptPassword(String password) throws NoSuchAlgorithmException, UnsupportedEncodingException {

    MessageDigest crypt = MessageDigest.getInstance("SHA-1");
    crypt.reset();
    crypt.update(password.getBytes("UTF-8"));

    return new BigInteger(1, crypt.digest()).toString(16);
}

25
投票

只需使用Apache Commons编解码器库。他们有一个叫做DigestUtils实用工具类

无需进入细节。


18
投票

由于之前使用Apache公地编解码器提及。我们建议由Spring球员以及(见春DOC DigestUtils)。例如。:

DigestUtils.sha1Hex(b);

绝对不会在这里用最精彩的答案。


5
投票

这不是正确打印,因为你需要使用Base64编码。在Java 8,你可以使用编码编码器Base64类。

public static String toSHA1(byte[] convertme) {
    md = MessageDigest.getInstance("SHA-1");
    return Base64.getEncoder().encodeToString((md.digest(convertme));
}

结果

这会给你你5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8的预期输出


2
投票

基部64表示SHA1哈希的:

String hashedVal = Base64.getEncoder().encodeToString(DigestUtils.sha1(stringValue.getBytes(Charset.forName("UTF-8"))));
© www.soinside.com 2019 - 2024. All rights reserved.