Android中的MD5哈希

98

我有一个简单的Android客户端需要与一个简单的C# HTTP监听器进行通信。 我想通过在POST请求中传递用户名/密码来提供基本级别的身份验证。

在C#中进行MD5哈希是微不足道的,并为我的需求提供了足够的安全性,但我似乎找不到如何在Android端执行此操作。

编辑:为了解决关于MD5弱点的担忧- C#服务器在我的Android客户端用户的PC上运行。 在许多情况下,他们将使用自己的LAN上的Wi-Fi访问服务器,但是,在自己的风险下,他们可能选择从互联网访问它。 此外,服务器上的服务需要将MD5直通到我无法控制的第三方应用程序。


6
不要使用MD5,应使用SHA512。 - SLaks
1
为什么?SHA512并不比MD5更难。你不想在五年后被困在使用MD5的遗留客户端中。 - SLaks
2
希望你在你的协议中使用随机数(nonce),这样你就可以防范重放攻击。 - sarnold
1
@NickJohnson:回答你的问题“为什么你会故意选择更弱的选项?”用另一个问题...你为什么觉得有必要评论我16个月前发布的问题?但是如果你真的想知道(如果你看一下在你上面的SLaks的评论),那是alpha阶段的代码,PC端(不是我写的)使用了MD5哈希。要求基本上是通过场景而不涉及额外的复杂性。当时我有大约10个alpha阶段的测试人员知道风险。自从我提出这个问题以来,更复杂的安全性已经被纳入。 - Squonk
1
...什么?不,这不仅是错误的,而且是非常危险的错误。 - Nick Johnson
显示剩余8条评论
16个回答

1
我使用了以下方法来获取传入字符串的MD5值:
public static String getMd5Key(String password) {

//        String password = "12131123984335";

        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            md.update(password.getBytes());

            byte byteData[] = md.digest();

            //convert the byte to hex format method 1
            StringBuffer sb = new StringBuffer();
            for (int i = 0; i < byteData.length; i++) {
                sb.append(Integer.toString((byteData[i] & 0xff) + 0x100, 16).substring(1));
            }

            System.out.println("Digest(in hex format):: " + sb.toString());

            //convert the byte to hex format method 2
            StringBuffer hexString = new StringBuffer();
            for (int i = 0; i < byteData.length; i++) {
                String hex = Integer.toHexString(0xff & byteData[i]);
                if (hex.length() == 1) hexString.append('0');
                hexString.append(hex);
            }
            System.out.println("Digest(in hex format):: " + hexString.toString());

            return hexString.toString();

        } catch (Exception e) {
            // TODO: handle exception
        }

        return "";
}

1
在我们的MVC应用程序中,我们为长参数生成代码。
using System.Security.Cryptography;
using System.Text;
    ...
    public static string getMD5(long id)
    {
        // convert
        string result = (id ^ long.MaxValue).ToString("X") + "-ANY-TEXT";
        using (MD5 md5Hash = MD5.Create())
        {
            // Convert the input string to a byte array and compute the hash. 
            byte[] data = md5Hash.ComputeHash(Encoding.UTF8.GetBytes(result));

            // Create a new Stringbuilder to collect the bytes and create a string.
            StringBuilder sBuilder = new StringBuilder();
            for (int i = 0; i < data.Length; i++)
                sBuilder.Append(data[i].ToString("x2"));

            // Return the hexadecimal string. 
            result = sBuilder.ToString().ToUpper();
        }

        return result;
    }

同时也适用于安卓应用程序(感谢 Andranik)

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
...
public String getIdHash(long id){
    String hash = null;
    long intId = id ^ Long.MAX_VALUE;
    String md5 = String.format("%X-ANY-TEXT", intId);
    try {
        MessageDigest md = java.security.MessageDigest.getInstance("MD5");
        byte[] arr = md.digest(md5.getBytes());
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < arr.length; ++i)
            sb.append(Integer.toHexString((arr[i] & 0xFF) | 0x100).substring(1,3));

        hash = sb.toString();
    } catch (NoSuchAlgorithmException e) {
        Log.e("MD5", e.getMessage());
    }

    return hash.toUpperCase();
}

0

MD5已经有点过时了,SHA-1是更好的算法,这里有一个例子

(正如他们在那篇文章中指出的那样,Java会自行处理此问题,无需特定于Android的代码。)


4
不 - 当我在2011年1月(19个月前)提出这个问题时,并不是希望得到MD5的替代方案,我不确定你为什么感觉需要在此时回答我的问题。 - Squonk
21
我回复是因为这符合stackoverflow的一般理念。无论事情发生多久之后,始终要为可能会遇到这个问题的人寻找更好的答案。至于建议使用SHA-1,我不知道你特别反对SHA-1,但许多其他人可能不会反对,所以这可能有助于未来遇到此类问题的其他人,并引导他们使用更现代的算法。 - Adam
3
我无法想象出任何一种情况,其中MD5是一个好选择,而SHA1是一个更好的选择。如果需要防碰撞,你需要使用SHA2而不是SHA1。如果你需要散列密码,你需要使用bcrypt或PBKDF2。在原帖作者的情况下,适当的解决方案可能是SSL。 - CodesInChaos
3
@Adam 这不是一个答案,这是一个评论。 - Antzi

0

其他建议中普遍存在太浪费 toHex() 转换的情况,真的是如此。

private static final char[] HEX_ARRAY = "0123456789ABCDEF".toCharArray();

public static String md5string(String s) {
    return toHex(md5plain(s));
}

public static byte[] md5plain(String s) {
    final String MD5 = "MD5";
    try {
        // Create MD5 Hash
        MessageDigest digest = java.security.MessageDigest.getInstance(MD5);
        digest.update(s.getBytes());
        return digest.digest();
    } catch (NoSuchAlgorithmException e) {
        // never happens
        e.printStackTrace();
        return null;
    }
}

public static String toHex(byte[] buf) {
    char[] hexChars = new char[buf.length * 2];
    int v;
    for (int i = 0; i < buf.length; i++) {
        v = buf[i] & 0xFF;
        hexChars[i * 2] = HEX_ARRAY[v >>> 4];
        hexChars[i * 2 + 1] = HEX_ARRAY[v & 0x0F];
    }
    return new String(hexChars);
}

答案与MD5相关的“更好”的toHex有关,因此它不是响应性的。注意:Donald Knuth 真正的问题在于程序员在错误的地方和错误的时间花费了太多精力来担心效率;过早的优化是编程中所有邪恶(或至少大部分)的根源。 - zaph

0

这对我来说完美地运作,我使用它在LIST数组上获取MD5(然后将其转换为JSON对象),但如果您只需要在数据格式中应用它,请使用您自己的 JsonObject 替换它。

特别是如果您与Python MD5实现不匹配,请使用此方法!

private static String md5(List<AccelerationSensor> sensor) {

    Gson gson= new Gson();
    byte[] JsonObject = new byte[0];
    try {
        JsonObject = gson.toJson(sensor).getBytes("UTF-8");
    } catch (UnsupportedEncodingException e) {
        e.printStackTrace();
    }

    MessageDigest m = null;

    try {
        m = MessageDigest.getInstance("MD5");
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    }

    byte[] thedigest = m.digest(JsonObject);
    String hash = String.format("%032x", new BigInteger(1, thedigest));
    return hash;


}

-1
提供的Scala语言解决方案(稍微简短):
def getMd5(content: Array[Byte]) =
    try {
        val md = MessageDigest.getInstance("MD5")
        val bytes = md.digest(content)
        bytes.map(b => Integer.toHexString((b + 0x100) % 0x100)).mkString
    } catch {
        case ex: Throwable => null
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接