我正在尝试用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}}?或者我完全错了吗?
答案 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)
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[]
)的函数。例如,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。基本上,一个字节可以具有从0
到255
(或从-128
到127
的值)的值,它等效于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);
}