Java String到SHA1

时间:2011-02-04 07:22:17

标签: java string sha1

我正在尝试用Java创建一个简单的String to 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 {1}}?或者我完全错了吗?

12 个答案:

答案 0 :(得分:165)

<强>更新
您可以使用Apache Commons Codec(版本1.7+)为您完成这项工作。

DigestUtils.sha1Hex(stringToConvertToSHexRepresentation)

感谢@ Jon Onstott提出此建议。


旧答案
将字节数组转换为十六进制字符串。 Real's How To tells you how

return byteArrayToHexString(md.digest(convertme))

和(从Real的方法复制)

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可以获得更紧凑的表示。 Apache Commons Codec API 1.4 ,有这个很好的实用工具来消除所有的痛苦。 refer here

答案 1 :(得分:62)

这是我将字符串转换为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;
}

答案 2 :(得分:51)

使用Guava Hashing class

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

答案 3 :(得分:28)

SHA-1(和所有其他哈希算法)返回二进制数据。这意味着(在Java中)它们产生byte[]byte数组表示任何特定字符,这意味着您不能像过去那样简单地将其转换为String

如果您需要String,那么您必须以可以表示为byte[]的方式格式化String(否则,只需保留)周围的byte[]

将任意byte[]表示为可打印字符的两种常用方法是BASE64或简单的十六进制字符串(即用两个十六进制数字表示每个byte)。看起来你正在尝试生成一个hex-String。

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

更好的解决方案是指定用于myString.getBytes()到 - String转换的编码,如下所示:byte[]。选择UTF-8(或代表每个Unicode字符的其他编码)是最安全的选择。

答案 4 :(得分:26)

只需使用apache commons编解码器库。他们有一个名为DigestUtils

的实用工具类

无需了解详情。

答案 5 :(得分:23)

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

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

答案 6 :(得分:18)

如前所述,使用apache commons编解码器。它也是由Spring工作人员推荐的(参见Spring doc中的DigestUtils)。 E.g:

DigestUtils.sha1Hex(b);

绝对不会在这里使用最受好评的答案。

答案 7 :(得分:4)

由于您需要使用Base64编码,因此无法正确打印。使用Java 8,您可以使用Base64编码器类进行编码。

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

<强>结果

这将为您提供5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8

的预期输出

答案 8 :(得分:2)

基础64 SHA1 Hash的表示:

String hashedVal = Base64.getEncoder().encodeToString(DigestUtils.sha1(stringValue.getBytes(Charset.forName("UTF-8"))));

答案 9 :(得分:2)

消息摘要(哈希)为byte [] in in byte [] out

消息摘要定义为使用原始字节数组并返回原始字节数组(也称为byte[])的函数。例如,SHA-1 (Secure Hash Algorithm 1)的摘要大小为160位或20字节。原始字节数组通常不能像character encodings那样解释为UTF-8,因为并非每个顺序中的每个字节都是合法的that编码。因此,使用以下命令将它们转换为String

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

可能会创建一些非法序列,或者具有指向未定义的Unicode映射的代码指针:

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

二进制文本编码

为此,使用binary-to-text编码。使用散列时,最常用的是HEX encoding or Base16。基本上,一个字节可以具有从0255(或从-128127的值)的值,它等效于0x00-{{ 1}}。因此,十六进制将使输出的所需长度加倍,这意味着20字节的输出将创建一个40个字符长的十六进制字符串,例如:

0xFF

请注意,不需要使用十六进制编码。您也可以使用类似base64的名称。十六进制通常是优选的,因为它易于被人类阅读并且具有定义的输出长度而无需填充。

您可以仅通过JDK功能将字节数组转换为十六进制:

2fd4e1c67a2d28fced849ee1bb76e7391b93eb12

但是请注意,new BigInteger(1, token).toString(16) 会将给定的字节数组解释为 number ,而不是字节字符串。这意味着将不输出前导零,并且结果字符串可能少于40个字符。

使用库编码为十六进制

您现在可以copy and paste an untested byte-to-hex method from Stack Overflow或使用Guava之类的大量依赖项。

要针对大多数与字节有关的问题提供最佳解决方案,我实现了一个实用程序来处理以下情况:bytes-java (Github)

要转换您的消息摘要字节数组,您可以做

BigInteger

或者您可以只使用内置的哈希功能

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

答案 10 :(得分:1)

这不起作用的原因是当你调用String(md.digest(convertme))时,你告诉Java将一系列加密字节解释为String。你想要的是将字节转换为十六进制字符。

答案 11 :(得分: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);
}