【问题标题】:Generate MD5 String in java在java中生成MD5字符串
【发布时间】:2015-02-22 20:11:14
【问题描述】:

我尝试在 java 中生成 md5 字符串。我写了一些代码,我可以生成 md5 字符串,但我有问题 我第一次给你看我的代码

public class MD5Hash
{

    public static void main(String args[])
    {

        computeMD5Hash("dbox#service" + "2014-12-24T18:34:49");
    }

    public static void computeMD5Hash(String password)
    {
        try
        {
            // Create MD5 Hash
            MessageDigest digest = java.security.MessageDigest.getInstance("MD5");

            digest.update(password.getBytes("UTF-16"));
            digest.update(password.getBytes());

            byte messageDigest[] = digest.digest();
            StringBuffer MD5Hash = new StringBuffer();

            for (int i = 0; i < messageDigest.length; i++)
            {
                String h = Integer.toHexString(0xFF & messageDigest[i]);

                while (h.length() < 2)
                    h = "0" + h;

                MD5Hash.append(h);
            }

            // result.setText("MD5 hash generated is: " + " " + MD5Hash);
            System.out.println("MD5 hash generated is: " + " " + MD5Hash);

        }
        catch (NoSuchAlgorithmException e)
        {
            e.printStackTrace();
        }
    }
}

正如我所说,我可以接收 md5 字符串,但我的朋友是 .net 开发人员,他也编写了代码,而我的 md5 字符串不同。这是他的 C# 代码

 public static string CreateMD5(string plain)
 {
     MD5 md5 = MD5.Create();
     byte[] inputBytes = Encoding.Unicode.GetBytes(plain);
     byte[] hashBytes = md5.ComputeHash(inputBytes);
     StringBuilder sb = new StringBuilder();

    for (int i = 0; i < hashBytes.Length; i++)
    {
        sb.Append(hashBytes[i].ToString("x2"));
    }

    return sb.ToString();
}

somethink 在我的 Java 代码中是错误的,因为我希望我的 Md5 字符串发送到服务器,当我将我的 md5 字符串发送到服务器时出现错误 - 我的朋友没有... 如果有人知道解决方案,我的代码有什么问题请帮助我 谢谢

【问题讨论】:

  • 您的 Java 代码没有经过优化 (StringBuffer?),但可以正常工作。为什么你认为不是?我针对已发布的哈希 here 对其进行了测试。
  • 您的代码是正确的,但不是很“Java 风格”。我已经为您的代码创建了 Java-style variant - 如果您有兴趣。如果您不是,请忽略它。
  • @Christian Hujer 谢谢。我插入了你的代码,但我在 toHexString 方法中有语法错误
  • @ElliottFrisch 因为正如我所说,我需要这个 md5 字符串来发送服务器。在 java 代码中,当我尝试发送时出现错误,而 C# 没有任何错误
  • 'echo -n "dbox#service2014-12-24T18:34:49" | md5sum' 给出 70f00e5bd872bd73ec6a8b4b8c8c9fef

标签: java c# .net md5 hashcode


【解决方案1】:

差异原因:编码

程序之间的区别在于用于将String的字符转换为字节的编码。

使用的C#程序UTF-16LE

您朋友的 C# 程序正在使用 Encoding.Unicode.GetBytes(),它默认为 UTF-16LE,因此会生成 ea15fbcf2123906e6fcb9f2a3b243492

Java 程序使用了其他东西

您的 Java 程序正在使用 String.getBytes(),它默认为您当前区域设置的编码(可能类似于 UTF-8Windows-1252,但显然是向后兼容 US-ASCII-7 的东西)并因此产生 70F00E5BD872BD73EC6A8B4B8C8C9FEF

同意某事

您必须决定实际应该使用哪种编码。我想说,对于这样的用例,使用UTF-8 是最常见的,并建议你们都同意UTF-8。但无论如何,你需要就某件事达成一致。

如何在 Java 中使用特定的编码,如 UTF-8UTF-16LE

换行

digest.update(password.getBytes());

digest.update(password.getBytes(StandardCharsets.UTF_16LE));

digest.update(password.getBytes(StandardCharsets.UTF_8));

您还可以使用StandardCharsets 中定义的字符集以外的字符集。在这种情况下,您需要使用String.getBytes()String 参数版本并处理UnsupportedEncodingException,如下所示:

try {
    digest.update(password.getBytes("ISO-8859-15"));
} catch (final UnsupportedEncodingException e) {
    throw new AssertionError(e);
}

更好的程序版本

  • varargs 用于 main(),以便在测试时使用 Md5Sum.main() 而不是 Md5Sum.main(new String[0]); 调用它。
  • print 重构为return
  • 使用Formatter 将字节转换为十六进制String,因为它更方便:它使用StringBuilder,它比StringBuffer 更快,并且它提供了format() 方法,可以大大提高转换效率更简单。
  • 创建变量final,因为我们打算永远不会重新分配它们。
  • for-loop 替换为foreach-loop,因为我们不使用索引变量。
  • 我们说我们希望MD5 可用,而不是打印堆栈跟踪并继续,如果不可用,则这是我们程序的内部错误并中止。与瘫痪的程序相比,崩溃的程序造成的损害更小。
public class Md5Sum {
    public static void main(final String... args) {
        final String md5sum = md5sum("dbox#service" + "2014-12-24T18:34:49");
        System.out.println("MD5 hash generated is: " + md5sum);
    }
    public static String md5sum2(final String plaintext) {
        try {
            final Formatter formatter = new Formatter();
            final MessageDigest digest = MessageDigest.getInstance("MD5");
            digest.update(plaintext.getBytes(StandardCharsets.UTF_16LE));
            for (final byte b : digest.digest())
                formatter.format("%02x", b);
            return formatter.toString();
        } catch (final NoSuchAlgorithmException e) {
            throw new AssertionError(e);
        }
    }
}

更好的程序版本

  • 将函数拆分为多个函数,以便它们可以单独使用(测试、重用)。
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Formatter;

import static java.nio.charset.StandardCharsets.UTF_16LE;

public class Md5Sum {
    public static void main(final String... args) {
        final String md5sum = md5sum("dbox#service" + "2014-12-24T18:34:49");
        System.out.println("MD5 hash generated is: " + md5sum);
    }

    public static String md5sum(final String plaintext) {
        return toHexString(md5sum(plaintext.getBytes(UTF_16LE)));
    }

    private static byte[] md5sum(final byte... bytes) {
        final MessageDigest digest = createMD5();
        digest.update(bytes);
        return digest.digest();
    }

    private static MessageDigest createMD5() {
        try {
            return MessageDigest.getInstance("MD5");
        } catch (final NoSuchAlgorithmException e) {
            throw new AssertionError(e);
        }
    }

    private static String toHexString(final byte... bytes) {
        final Formatter formatter = new Formatter();
        for (final byte b : bytes)
            formatter.format("%02X", b);
        return formatter.toString();
    }
}

【讨论】:

    【解决方案2】:

    在 C# 示例 Encoding.Unicode 中,您可以将 UTF-16 字符串传递给摘要,而在 Java 端,将 UTF-8 字符串传递给摘要。

    【讨论】:

    • 感谢我添加了 digest.update(password.getBytes("UTF-16"));在我的代码中,但我也收到了不同的 md5。我不知道出了什么问题
    • 我不了解 C#/.Net,但可能是它使用 UTF-16 和 Little Endian,我很确定 Java 会给你 UTF-16 和 Big Endian .如果您需要与 C# 程序相同的哈希/行为,您可能会尝试显式使用 UTF-16LE。
    • Java String.getBytes() 使用平台的默认字符集将此字符串编码为字节序列,并将结果存储到新的字节数组中。试试 password.getBytes(Charset.forName("UTF-16"))
    • @lonewasp 我也添加了这一行,但我收到了相同的 md5 字符串 :(
    • 按照 Christian Hujer 的建议尝试 UTF-16LE 或 UTF-16BE。唯一需要检查的是尾随零进入 MD5 十六进制转储中的摘要或小/大字母。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-04-01
    • 2017-11-08
    • 2021-09-28
    • 2018-12-10
    • 1970-01-01
    • 2012-03-13
    • 1970-01-01
    相关资源
    最近更新 更多