Asked  7 Months ago    Answers:  5   Viewed   37 times

I have a SQL table with usernames and passwords. The passwords are encoded using MessageDigest's digest() method. If I encode a password - let's say "abcdef12" - with MessageDigest's digest() method and then convert it to hexadecimal values, the String is different than if I do the same using PHP's SHA1-method. I'd expect these values to be exactly the same though.

Code that is used to encode the passwords:

MessageDigest md = MessageDigest.getInstance("SHA-1");
byte[] passbyte;
passbyte = "abcdef12".getBytes("UTF-8");
passbyte = md.digest(passbyte);

The conversion of the String to hexadecimal is done using this method:

public static String convertStringToHex(String str) {

    char[] chars = str.toCharArray();

    StringBuffer hex = new StringBuffer();
    for (int i = 0; i < chars.length; i++) {
        hex.append(Integer.toHexString((int) chars[i]));
    }

    return hex.toString();
}

Password: abcdef12

Here's the password as returned by a lot of SHA1-hash online generators and PHP SHA1()-function: d253e3bd69ce1e7ce6074345fd5faa1a3c2e89ef

Here's the password as encoded by MessageDigest: d253e3bd69ce1e7ce674345fd5faa1a3c2e2030ef

Am I forgetting something?

Igor.

Edit: I've found someone with a similar problem: C# SHA-1 vs. PHP SHA-1...Different Results? . The solution was to change encodings.. but I can't change encodings on the server-side since the passwords in that SQL-table are not created by my application. I use client-side SHA1-encoding using a JavaScript SHA1-class (more precisely: a Google Web Toolkit-class). It works and encodes the string as expected, but apparently using ASCII characters?..

 Answers

68

It has nothing to do with the encodings. The output would be entirely different.

For starters, your function convertStringToHex() doesn't output leading zeros, that is, 07 becomes just 7.

The rest (changing 89 to 2030) is also likely to have something to do with that function. Try looking at the value of passbyte after passbyte = md.digest(passbyte);.

Wednesday, March 31, 2021
 
petersaints
answered 7 Months ago
40

Over 3 years later I ran into the same issue, but this time I figured out the problem. Here is the solution to anyone that stumbles upon this question:

I was using:

sha1("qwerty") == sha1("qwerty")
Base64.encodeToString("qwerty".getBytes(), Base64.DEFAULT) == base64_encode("qwerty")
sha1(Base64.encodeToString("qwerty".getBytes(), Base64.DEFAULT)) != sha1(base64_encode("qwerty"))

The problem with this is the Base64.DEFAULT, the default behavior of Base64 wraps the string (adds n to string). In order to get the same result as the PHP method you should use Base64.NO_WRAP:

sha1("qwerty") == sha1("qwerty")
Base64.encodeToString("qwerty".getBytes(), Base64.NO_WRAP) == base64_encode("qwerty")
sha1(Base64.encodeToString("qwerty".getBytes(), Base64.NO_WRAP)) == sha1(base64_encode("qwerty"))

After I made this change it started to work

Saturday, May 29, 2021
 
jsuissa
answered 5 Months ago
44

UPDATE
You can use Apache Commons Codec (version 1.7+) to do this job for you.

DigestUtils.sha1Hex(stringToConvertToSHexRepresentation)

Thanks to @Jon Onstott for this suggestion.


Old Answer
Convert your Byte Array to Hex String. Real's How To tells you how.

return byteArrayToHexString(md.digest(convertme))

and (copied from Real's How To)

public static String byteArrayToHexString(byte[] b) {
  String result = "";
  for (int i=0; i < b.length; i++) {
    result +=
          Integer.toString( ( b[i] & 0xff ) + 0x100, 16).substring( 1 );
  }
  return result;
}

BTW, you may get more compact representation using Base64. Apache Commons Codec API 1.4, has this nice utility to take away all the pain. refer here

Monday, June 7, 2021
 
muaddhib
answered 5 Months ago
39

In fact they do agree.
As Hans Doggen already noted PHP outputs the message digest using hexadecimal notation unless you set the raw output parameter to true.
If you want to use the same notation in Java you can use something like

for (byte b : digest) {
    System.out.format("%02x", b);
}
System.out.println();

to format the output accordingly.

Saturday, June 12, 2021
 
MannfromReno
answered 5 Months ago
85

This line is wrong, since you interpret UTF8 encoded data as if it was Unicode encoded:

NSString *unicodePassword = [[NSString alloc] initWithData:data encoding:NSUnicodeStringEncoding];

Replce the second line with: NSData *data = [password dataUsingEncoding:NSUnicodeStringEncoding];

The 2 first bytes in data is a BOM (Byte order mark).

Remove these 2 bytes with data = [NSData dataWithBytes:[data bytes] + 2 length:[data length] - 2];

...and then hash that data any you will have the same hash as in C#.

Friday, September 24, 2021
 
ioleo
answered 1 Month ago
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :