4

I know there are several questions like this around, but I tried every single solution I found on stackoverflow and I still haven't got the expected result.

I'm trying to convert a string to sha1 in Java and PHP, but I'm getting different results. The string is generated randomly. I checked the string on both ends and they are the same (even trying a online comparison tool).

This is the same code I use in another app and it's working there, but not in this case.

One string I tried to hash with sha1 is: UgJaDVYEClRUD1cAAVUBVwRTB1MDAA9SBgcDBwNXAwNZBQdUAAACBA==

Java result: 72c9bbe7eed0efe5e82ea9568136d8f52347259e

PHP result: f720d73d18a7bb9cf36808af17ce40621ebfb405

Java Code

public static String sha1(String toHash)
{
    String hash = null;
    try
    {
        MessageDigest digest = MessageDigest.getInstance("SHA-1");
        byte[] bytes = toHash.getBytes("ASCII"); //I tried UTF-8, ISO-8859-1...
        digest.update(bytes, 0, bytes.length);
        bytes = digest.digest();
        StringBuilder sb = new StringBuilder();
        for(byte b : bytes)
        {
            sb.append(String.format("%02X", b));
        }
        hash = sb.toString();
    }
    catch(NoSuchAlgorithmException e)
    {
        e.printStackTrace();
    }
    catch(UnsupportedEncodingException e)
    {
        e.printStackTrace();
    }
    return hash.toLowerCase(Locale.ENGLISH);
}

PHP code

sha1("UgJaDVYEClRUD1cAAVUBVwRTB1MDAA9SBgcDBwNXAwNZBQdUAAACBA==");

Any help would be appreciated

Update

In Java & PHP I was doing the following:

Java

String toHash = "qwerty";
String hash = sha1(toHash); //Prints: b1b3773a05c0ed0176787a4f1574ff0075f7521e

toHash = Base64.encodeToString(toHash.getBytes("ASCII"), Base64.DEFAULT);
hash = sha1(toHash); //Prints: 88bfb2d77c3b42823bab820c1737f03c97d87c1b

PHP

$toHash = "qwerty";
sha1($toHash); //Prints: b1b3773a05c0ed0176787a4f1574ff0075f7521e

sha1(base64_encode($toHash)); //Prints: 278aa0e8dde2af58a4eed613467da219a35c5278

I guess that the Base64 encoding is doing something to the string that is different on PHP and Java, any thoughts on why?

UPDATE 2

I should have been more clearer, sorry for that, what I mean is:

The output of Java

sha1(Base64.encodeToString("qwerty".getBytes("ASCII"), Base64.DEFAULT));

is different that the output of PHP

sha1(base64_encode("qwerty"));

UPDATE 3

although both base64 encoded string are equal cXdlcnR5.

Basically:

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

I already dropped the base64 encoding on the strings that I hash, but I still would like to know what I could have done to make it work.

Marco Batista
  • 1,410
  • 1
  • 20
  • 38
  • Your hashes might be encoded differently. E.g. if using hex encoding you have to ensure that you do this on both php and java – DarkLeafyGreen Nov 17 '13 at 18:37
  • Yep, make sure you convert the byte-array to a hexadecimal string properly. – Blacklight Nov 17 '13 at 18:39
  • You are using toHash in the Base64 encodeToString 2 times. I doubt that that's your intention. In Java, your are Base64 encoding "qwerty" and then calculating the sha1 while in PHP you do it the other way arround. – Lieven Keersmaekers Nov 17 '13 at 20:08

2 Answers2

4

Edit

you are using the toHash variable twice in the encodeToString method making your second line of code redundant.

this code

String toHash = "qwerty";
String hash = sha1(toHash); //Prints: b1b3773a05c0ed0176787a4f1574ff0075f7521e

toHash = Base64.encodeToString(toHash.getBytes("ASCII"), Base64.DEFAULT);
hash = sha1(toHash); //Prints: 88bfb2d77c3b42823bab820c1737f03c97d87c1b

is equivalent to this code

String toHash = "qwerty";
toHash = Base64.encodeToString(toHash.getBytes("ASCII"), Base64.DEFAULT);
hash = sha1(toHash); //Prints: 88bfb2d77c3b42823bab820c1737f03c97d87c1b

So essentially in java you are

  • getting Base64 for "qwerty"
  • getting the sha1 on that result

While using PHP your are

  • getting the sha1 for "qwerty"
  • getting the Base64 on that result

I assume you've mistyped

Lieven Keersmaekers
  • 57,207
  • 13
  • 112
  • 146
  • It prints the correct result... which gets me even more confused to where is the problem :/ – Marco Batista Nov 17 '13 at 19:30
  • You tried it yourself? What's the diff between this code and yours? Whata java version are you using *(not that is should matter)*? – Lieven Keersmaekers Nov 17 '13 at 19:39
  • Yes I did, see the edit I just made for a more detailed explanation. I'm using Java 1.7.0_45-b18 – Marco Batista Nov 17 '13 at 19:59
  • Sorry I should have been clearer, that was just to illustrate that the sha1 of the base64 encoded string is different on Java and PHP. I actually do one or the other. Basically what I meant was: `sha1(Base64.encodeToString("qwerty".getBytes("ASCII"), Base64.DEFAULT)) != sha1(base64_encode("qwerty"))` The first part of that is Java and the part after `!=` is PHP. As soon as I can edit my question again I'll add this. – Marco Batista Nov 17 '13 at 20:43
  • As per your latest edit, you say that the mismatch is in the Base64 encoding, not in the sha1? I suggest you edit your question or close this one and create a new with only the information necessary. The sha calculation can be dropped entirely. – Lieven Keersmaekers Nov 17 '13 at 21:14
  • I have too many things on my head and I keep forgetting things... I meant to add this in the edit: Java base64 encode is equals to PHP encode, both output `cXdlcnR5`, basically up until the sha1 part both the PHP logs and the Java logs are in sync. The sha1 part is where the logs start to differ as both print different results. – Marco Batista Nov 17 '13 at 21:24
  • @MBat - Don't sweat about it but that brings us right back to where we started :). I still believe it would be a good thing to ask in a new question and provide a SSCCE *(drop the base64 encoding entirely as it only clutters the question)* – Lieven Keersmaekers Nov 18 '13 at 08:30
1

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

Marco Batista
  • 1,410
  • 1
  • 20
  • 38