Difference between Java and php5 MD5 Hash

大兔子大兔子 提交于 2019-12-18 13:49:07

问题


I'm facing kind of a strange issue which is related MD5-Hashes in Java and php5. I figured that unter certain circumstances the following code does not generate correct MD5 hashes:

public static String getMD5Hash(String string)
{
    try 
    {
        MessageDigest md5 = MessageDigest.getInstance("MD5");
        md5.update(string.getBytes());
        byte[] digest = md5.digest();

        string = byteArrToHexString(digest);
    } 
    catch (NoSuchAlgorithmException e1) 
    {
        e1.printStackTrace();
    }

    return string;
}

private static String byteArrToHexString(byte[] bArr)
{
    StringBuffer sb = new StringBuffer();

    for (int i = 0; i < bArr.length; i++) 
    {
        int unsigned = bArr[i] & 0xff;
        sb.append(Integer.toHexString((unsigned)));
    }

    return sb.toString();
}

I had to migrate an existing user database where the passwords where stored in php5 MD5. Now some of the users, not all, can't login because my Java code does not produce the correct MD5 hash.

Any ideas what's wrong with the above?


回答1:


byteArrToHexString does not convert bytes <0x10 correctly, you need to pad them with zeros.

Example:

int unsigned = bArr[i] & 0xff;
if (unsigned < 0x10)
  sb.append("0");
sb.append(Integer.toHexString((unsigned)));



回答2:


So funny... I just encountered a problem with MD5 hashed passwords myself. The problem in my case was the encoding of the original password into a byte[].

I advise you to find out exactly which encoding was used to hash the passwords previously, and change line 6 of the code above to

md5.update(string.getBytes("UTF-8"));

(Of course, this is just an example... find out the correct Charset to use as a parameter)

BTW, I suppose you have your reasons, but why not have the hashing method do this?

return new String(digest, "UTF-8");

Yuval =8-)




回答3:


You are missing:

md5.reset();

before doing an update()

Check Java md5 example with MessageDigest




回答4:


I've found 2 solutions (found from here and from the other answers) :

object MD5Util {
    private val messageDigest: MessageDigest?

    init {
        val testMd =
                try {
                    MessageDigest.getInstance("MD5")
                } catch (e: Exception) {
                    null
                }
        messageDigest = testMd
    }

    private fun hex(array: ByteArray): String {
        val sb = StringBuilder()
        for (b in array)
            sb.append(Integer.toHexString((b.toInt() and 0xFF) or 0x100).substring(1, 3))
        return sb.toString()
    }

    @JvmStatic
    fun md5Hex(message: String): String {
        if (messageDigest != null)
            try {
                return hex(messageDigest.digest(message.toByteArray(charset("CP1252"))))
            } catch (e: Exception) {
                throw e
            }
        throw Exception("messageDigest not found")
    }

    @JvmStatic
    fun md5(s: String): String {
        if (messageDigest != null)
            try {
                val hash: ByteArray = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT)
                    messageDigest.digest(s.toByteArray(StandardCharsets.UTF_8))
                else
                    messageDigest.digest(s.toByteArray(charset("UTF-8")))
                val sb = StringBuilder()
                for (aHash in hash) {
                    val hex = Integer.toHexString(aHash.toInt())
                    if (hex.length == 1)
                        sb.append('0').append(hex[hex.length - 1])
                    else
                        sb.append(hex.substring(hex.length - 2))
                }
                return sb.toString()
            } catch (e: Exception) {
                throw e
            }
        throw Exception("messageDigest not found")
    }
}

According to some benchmarks, I can say that the md5 function is about twice faster than the md5Hex function. Here's the test:

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        AsyncTask.execute {
            val emailList=ArrayList<String>()
            for (i in 0 until 100000)
                emailList.add( generateRandomEmail(10))
            var startTime = System.currentTimeMillis()
            for (email in emailList)
                MD5Util.md5(email)
            var endTime = System.currentTimeMillis()
            Log.d("AppLog", "md5 - time taken: ${endTime - startTime}")
            startTime = System.currentTimeMillis()
            for (email in emailList)
                MD5Util.md5Hex(email)
            endTime = System.currentTimeMillis()
            Log.d("AppLog", "md5Hex - time taken: ${endTime - startTime}")
        }
    }

    companion object {
        private const val ALLOWED_CHARS = "abcdefghijklmnopqrstuvwxyz" + "1234567890" + "_-."

        @Suppress("SpellCheckingInspection")
        fun generateRandomEmail(@IntRange(from = 1) localEmailLength: Int, host: String = "gmail.com"): String {
            val firstLetter = RandomStringUtils.random(1, 'a'.toInt(), 'z'.toInt(), false, false)
            val temp = if (localEmailLength == 1) "" else RandomStringUtils.random(localEmailLength - 1, ALLOWED_CHARS)
            return "$firstLetter$temp@$host"
        }
    }
}

gradle file has this:

implementation 'org.apache.commons:commons-lang3:3.7'


来源:https://stackoverflow.com/questions/1057041/difference-between-java-and-php5-md5-hash

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!