Archive

Archive for July, 2010

Howto implement MySQL’s OLD_PASSWORD() in Java

July 23rd, 2010 makii Comments off

Like most Software Engineers I don’t have the luxury to start with an greenfield strategy. Most times we know a good and viable solution to a problem, but cannot implement it due to restrictions which come with legacy systems and stuff out of our control.

Recently I had to migrate Newsletter subscribers to a newly created subscription system which uses an Oracle Database (I would have preferred PostgreSQL) rather than a MySQL, as the old system does.

Programmers are lazy, and as expected the developers of the old system used the OLD_PASSWORD(str) function from the database available to hash the password entered by the user. This is a very convenient way to protect the users’ login credentials, but rather bad when migrating to another system which has different or none implementations of this functionality. So what do we do? The options are:

  • Send every user a new password. Bad, we don’t want to harass them with our technical issues.
  • Force them to set a new password when they log in the next time. See above
  • Try to find a solution to validate the password against the old password hash.

As MySQL is widely used and a lot of data migration happens to and from, someone must have been run in this issue already, and most likely there is a solution to this problem in the net. And there is. I found a reimplementation of the OLD_PASSWORD() function in C# at yourhelpcenter.de (attention, german) and together with my coworker Maurice we ported it to Java, resulting in this piece of code:

public static String mysqlOldPassword(byte[] password) {
        int[] result = new int[2];
        int nr = 1345345333;
        int add = 7;
        int nr2 = 0x12345671;
        int tmp;

        int i;
        for (i = 0; i < password.length; i++) {
            if (password[i] == ' ' || password[i] == '\t')
                continue;

            tmp = (int) password[i];
            nr ^= (((nr & 63) + add) * tmp) + (nr << 8);
            nr2 += (nr2 << 8) ^ nr;
            add += tmp;
        }

        result[0] = nr & ((1 << 31) - 1);
        int val = ((1 << 31) - 1);
        result[1] = nr2 & val;
        String hash = String.format("%08x%08x",result[0],result[1]);
        return hash.toLowerCase();
    }

I give no guarantee this will work in all cases. My IDE complains all over the place about possible integer overflows. The usage of Integer.toHexString()did not work either, as the resulting String is not padded up with zeroes.

Finally, some Unit Tests for the interested user:

    @Test
    public void testOldPassword() throws Exception {
        final String expected = "0414ac6137ee1adc";
        byte[] bytes = "fooo".getBytes("UTF8");
        String foo = mysqlOldPassword(bytes);
        assertEquals(expected, foo);
    }

    @Test
    public void testOldPassword2() throws Exception {
        final String expected = "3fa0dce62ba931b5";
        byte[] bytes = "hastewas".getBytes("UTF8");
        String foo = mysqlOldPassword(bytes);
        assertEquals(expected, foo);
    }

Have fun with it!

Categories: Java, Technology, Web Tags: , , , ,