UNIX lmhash in Java

Hello,

Currently I'm developing an extension for a database management program that was done in Perl. My component is done using Java. Now I have a problem because the passwords for the users that are stored in the database are all encrypted using the UNIX lmhash function. I was told that the passwords are encrypted using MD5 so I used the MessageDigest class to encrypt my passwords using MD5 as well. But the result I'm getting is different.

Any ideas?

This is my first time on this forum so I'm sorry if this question was previously addressed before.

Regards,

Toar

[609 byte] By [Toara] at [2007-10-2 21:52:15]
# 1
Are you sure your hash comes from Unix? The only reference Ive heard of LM hash in is with Microsoft Windows. http://en.wikipedia.org/wiki/LM_hashWhats the library and function call you're using?
cdelikata at 2007-7-14 1:08:09 > top of Java-index,Security,Cryptography...
# 2

Hi,

I am not sure honestly. I was first told that the passwords are encrypted using MD5, but after I asked for the code where the original developers encrypt their password, I am given this perl script.

use Crypt::SmbHash qw (lmhash);

###########################################

sub generate_encrypted_password

{

$_=shift;

return lmhash($_);

}

##########################

my $pd = lmhash($password);

And then the program continues to compare $pd with the values of the password that are in the database.

I think you might be right though because all the search I found on LM Hash talks about Windows' too. Sorry, I'm in a position where I can't constantly communicate with the original developer so some of the thing I mentioned might be wrong. I'm starting to think that MD5 and the MessageDigest class will have nothing to do with this

Toara at 2007-7-14 1:08:09 > top of Java-index,Security,Cryptography...
# 3

Ok-

This makes sense. They used some SMB package and SMB is a windows

protocol (samba being the unix port).

I found what looks like java implementations of the lmhash. I cant verifiy

this stuff myself right now, but I can take a closer look later tonite...

There's a method called lmhash that might be what you're looking for.

http://davenport.sourceforge.net/ntlm.html

If that doesnt cut it, you could take a look at the java impl of samba:

http://jcifs.samba.org/

cdelikata at 2007-7-14 1:08:09 > top of Java-index,Security,Cryptography...
# 4

I'm just looking now to use the NTLM Authentication protocol on

http://davenport.sourceforge.net/ntlm.html

I can't really test it because I don't know the actual passwords though.

But the encrypted passwords in my database are all in 32 alphanumberic characters string with capitalized letters and numbers.

Thank you for the links

Toara at 2007-7-14 1:08:09 > top of Java-index,Security,Cryptography...
# 5

Cant make a test user or something? Dont have a dev system set up

somewhere?

If neither of those conditions exist, all you need to do is run the perl

function lmhash() with some text then run it again with the java!

Anyway, Im looking thru the SmbHash.pm (perl) source and it looks like it

might not be doing exactly the same thing...

cdelikata at 2007-7-14 1:08:09 > top of Java-index,Security,Cryptography...
# 6

OK-

I just verified that the java and perl code generate the same hash.

Both the perl lmhash function and the java one return

8A6D8380CAC58F2201FC5A6BE7BC6929

when the password is "thisisatest".

Here's the java that I used. Note the lmHash, createDESKey, and oddParity

functions came from http://davenport.sourceforge.net/ntlm.html#lmHash.

import java.security.Key;

import javax.crypto.Cipher;

import javax.crypto.spec.SecretKeySpec;

public class LMHash {

public static void main(String [] args) {

try {

System.out.println(toHexString(LMHash.lmHash(args[0]), true));

} catch (Exception e) {

System.out.println("ERROR: " + e.getMessage());

}

}

/**

* Creates the LM Hash of the user's password.

*

* @param password The password.

*

* @return The LM Hash of the given password, used in the calculation

* of the LM Response.

*/

private static byte[] lmHash(String password) throws Exception {

byte[] oemPassword = password.toUpperCase().getBytes("US-ASCII");

int length = Math.min(oemPassword.length, 14);

byte[] keyBytes = new byte[14];

System.arraycopy(oemPassword, 0, keyBytes, 0, length);

Key lowKey = createDESKey(keyBytes, 0);

Key highKey = createDESKey(keyBytes, 7);

byte[] magicConstant = "KGS!@#$%".getBytes("US-ASCII");

Cipher des = Cipher.getInstance("DES/ECB/NoPadding");

des.init(Cipher.ENCRYPT_MODE, lowKey);

byte[] lowHash = des.doFinal(magicConstant);

des.init(Cipher.ENCRYPT_MODE, highKey);

byte[] highHash = des.doFinal(magicConstant);

byte[] lmHash = new byte[16];

System.arraycopy(lowHash, 0, lmHash, 0, 8);

System.arraycopy(highHash, 0, lmHash, 8, 8);

return lmHash;

}

/**

* Creates a DES encryption key from the given key material.

*

* @param bytes A byte array containing the DES key material.

* @param offset The offset in the given byte array at which

* the 7-byte key material starts.

*

* @return A DES encryption key created from the key material

* starting at the specified offset in the given byte array.

*/

private static Key createDESKey(byte[] bytes, int offset) {

byte[] keyBytes = new byte[7];

System.arraycopy(bytes, offset, keyBytes, 0, 7);

byte[] material = new byte[8];

material[0] = keyBytes[0];

material[1] = (byte) (keyBytes[0] << 7 | (keyBytes[1] & 0xff) >>> 1);

material[2] = (byte) (keyBytes[1] << 6 | (keyBytes[2] & 0xff) >>> 2);

material[3] = (byte) (keyBytes[2] << 5 | (keyBytes[3] & 0xff) >>> 3);

material[4] = (byte) (keyBytes[3] << 4 | (keyBytes[4] & 0xff) >>> 4);

material[5] = (byte) (keyBytes[4] << 3 | (keyBytes[5] & 0xff) >>> 5);

material[6] = (byte) (keyBytes[5] << 2 | (keyBytes[6] & 0xff) >>> 6);

material[7] = (byte) (keyBytes[6] << 1);

oddParity(material);

return new SecretKeySpec(material, "DES");

}

/**

* Applies odd parity to the given byte array.

*

* @param bytes The data whose parity bits are to be adjusted for

* odd parity.

*/

private static void oddParity(byte[] bytes) {

for (int i = 0; i < bytes.length; i++) {

byte b = bytes[i];

boolean needsParity = (((b >>> 7) ^ (b >>> 6) ^ (b >>> 5) ^

(b >>> 4) ^ (b >>> 3) ^ (b >>> 2) ^

(b >>> 1)) & 0x01) == 0;

if (needsParity) {

bytes[i] |= (byte) 0x01;

} else {

bytes[i] &= (byte) 0xfe;

}

}

}

private static String toHexString(byte [] bytes, boolean dashing) {

StringBuffer hexStr = new StringBuffer();

System.out.println(bytes.length);

for (int i = 0; i < bytes.length; i++) {

int hex = (0xff & bytes[i]);

String tmp = Integer.toHexString(hex);

tmp = (tmp.length() == 1) ? "0" + tmp : tmp;

if (dashing) {

hexStr.append(tmp.toUpperCase());

if ((i+1) != bytes.length) hexStr.append('-');

} else {

hexStr.append(tmp);

}

}

return hexStr.toString();

}

}

cdelikata at 2007-7-14 1:08:09 > top of Java-index,Security,Cryptography...
# 7
Hi,I was just able to generate the password from the original software today, I don't have UNIX on my computer so I couldn't test it yesterday but the function works. Thank youRegards,Toar
Toara at 2007-7-14 1:08:09 > top of Java-index,Security,Cryptography...
# 8

Just so you know- you didnt need a unix system to test this, you just

needed perl. The Crypt::SmbHash library implements all its functions in pure perl.

I know perl tends to be associated with unix systems, and

rightly so, but there is a popular win32 version out there:

http://www.activestate.com/Products/ActivePerl/

cdelikata at 2007-7-14 1:08:09 > top of Java-index,Security,Cryptography...