Java and Php returns different hashes - java

So, PHP code:
$result = hash("whirlpool","xxx".$password."zzz");
JAVA:
import gnu.crypto.Registry;
import gnu.crypto.hash.HashFactory;
import gnu.crypto.hash.IMessageDigest;
public class WhirlpoolHash {
String result;
WhirlpoolHash(String pass) {
String to_encode = "xxx"+pass+"zzz";
IMessageDigest old_encoder = HashFactory.getInstance(Registry.WHIRLPOOL_HASH);
byte[] input = to_encode.getBytes();
old_encoder.update(input, 0, input.length);
byte[] digest = old_encoder.digest();
this.result = gnu.crypto.util.Util.toString(digest).toLowerCase();
}
public String Get() {
return this.result;
}
}
And the result vars are different. I need java class to return the same value as php does.
I have passwords stored in MySQL DB UTF-8 encoded generated by PHP and need to compare it with data sent by JavaFX app.
Of course i can send unencrypted password, and do it with php but I dont whant to.

So Java example for encrypting pwd with whirlpool algorithm using gnu-crypto jar was an answer.
I dont know why but jonelo.jacksum.JacksumAPI gives the result same as PHP.

Late response, but in case it helps someone else.
I had almost the exact same issue and used Bouncy Castle in Java. After some trial and error, I got the hashes with Whirlpool to match my PHP hash, which looked similar to yours. Assuming you pass in the password:
WhirlpoolDigest messageDigest = new WhirlpoolDigest();
final String convertedHash = "xxx" + password + "yyy";
messageDigest.reset();
final byte[] bytes = convertedHash.getBytes();
messageDigest.update(bytes, 0, bytes.length);
byte[] hash = new byte[messageDigest.getDigestSize()];
messageDigest.doFinal(hash, 0);
System.out.println(Hex.toHexString(hash));
The biggest issue for me was the final steps - the doFinal() and the Hex.toHexString() ...
My maven dependency looked like this:
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-ext-jdk15on</artifactId>
<version>1.64</version>
</dependency>

Related

Java Digest Hash and PHP Hash are different

I'm trying to authenticate a webhook from starling bank on a PHP 7.0.22 (Apache/2.4.6 (Red Hat Enterprise Linux)) server.
I've been told by support that the following java code is being used to generate the digest
private String calculateSignature(String sharedSecret, String requestJson) {
try {
String contentToDigest = sharedSecret + requestJson;
MessageDigest messageDigest = MessageDigest.getInstance("SHA-512");
byte[] digest = messageDigest.digest(contentToDigest.getBytes());
return Base64.getEncoder().encodeToString(digest);
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("Error calculating digest for payload [" + requestJson + "]", e);
}
}
The sharedSecret I already have and the requestJson I take from the webhook POST using:
$requestJson=file_get_contents('php://input') ;
my php code to generate the hash is as follows:
$concatenated_string=$sharedSecret . json_encode($requestJson) ;
$generated_hash=base64_encode(hash('sha512', $concatenated_string ));
This doesn't give the same hash. Whilst hacking to try and find an answer, I've also tried the following :
$concatenated_string=$sharedSecret . $requestJson ;
and different hash types and options:
$generated_hash=base64_encode(hash('sha512', $concatenated_string, true ))
$generated_hash=base64_encode(openssl_digest($concatenated_string, 'sha512')) ;
base64_encode and hash are effectively doing the same thing in this case:
https://stackoverflow.com/a/11195855/3323777
You should specify third argument as TRUE at your php code to match the java version:
raw_output - Setting to TRUE will return as raw output data, otherwise the return value is binhex encoded.
http://php.net/manual/ru/function.openssl-digest.php
I've ran your both snippets on java and php and found not difference when encoding a string "test". I advise you to output the json payloads to two files on both environments and use diff to compare them.

Generating a dynamic password reset link

To reset my password I want to send the user a link to site/account/{hash} where {hash} is a hash of the user's password and a timestamp.
I have the following code to hash only the email and have a readable link:
String check = info.mail;
MessageDigest md = MessageDigest.getInstance("SHA-1");
String checkHash = Base64.encodeBase64String(md.digest(check.getBytes()));
if(checkHash.equals(hash)){
return ResponseEntity.ok("Password reset to: " + info.password);
}else{
return ResponseEntity.ok("Hash didn't equal to: " + checkHash);
}
The problem is that when I convert this to Base64 it may include / signs what will mess up my links and checking of the hash.
I can simply replace any unwanted signs by something else after the hashing but is there some other way to have your hash only include a certain part of codes?
Also I know the returns are still sent unsafe but this is just for testing and debugging.
The RFC 3548 specifies a variant often called "base64url" specifically designed for that purpose. In this variant, + and / are replaced by - and _.
Java 8 has built-in support with the new Base64 class. If you're stuck with an older version, the Base64 class of Apache Commons can be configured to be url safe by using the new Base64(true) constructor.
Other options might be:
Don't use Base64, but transfer the bytes as hexadecimal
representation (which will not contain any special characters):
String checkHash = toHex(md.digest(check.getBytes()));
with
private static String toHex(byte[] bytes) {
StringBuilder sb = new StringBuilder();
for (byte b : bytes) {
sb.append(String.format("%02X", b));
}
return sb.toString();
}
Use URL encoding/decoding on the generated hash (that's what you already know)

decrypt the encrypted PHP string to Android Java

I want to encrypt the final grades of students in PHP and decrypt it in Android Java. I referred my codes here but it returns wrong value.
This is my PHP encryption function
function encode5t($value1){
for($i=0;$i<3;$i++)
{
$value1=base64_encode(strrev($value1));
}
return $value1;
}
Call the function:
foreach ($rows as $row){
$post["cSemester"] = $row["cSemester"];
$post["cSchoolYear"] = $row["cSchoolYear"];
$post["cSubjectCode"] = $row["cSubjectCode"];
$post["cDescription"] = $row["cDescription"];
$post["nFGrade"] = encode5t($row["nFGrade"]);
$post["nCGrade"] = $row["nCGrade"];
$post["nCredit"] = $row["nCredit"];
//update our response JSON data
array_push($response["posts"], $post);
}
echo json_encode($response);
And this is my Java code.
vGrades = json.getJSONArray(TAG_POSTS);
for (int i = 0; i < vGrades.length(); i++) {
JSONObject c = vGrades.getJSONObject(i);
String cSemester = c.getString(TAG_SEMESTER);
String cSchoolYear = c.getString(TAG_SCHOOLYEAR);
String cSubjectCode = c.getString(TAG_SUBJECTCODE);
String cDescription = c.getString(TAG_DESCRIPTION);
String encrypted_string = c.getString(TAG_FINALGRADE);
String nCGrade = c.getString(TAG_COMPLETIONGRADE);
String nCredit = c.getString(TAG_CREDIT);
HashMap<String, String> map = new HashMap<String, String>();
try{
byteArray = Base64.decode(encrypted_string, Base64.DEFAULT);
decrypt = new String(byteArray, "UTF-8");
}catch (UnsupportedEncodingException e) {
e.printStackTrace();
} // this is where I want to decrypt it.
nFGrade = decrypt;
map.put(TAG_SEMESTER, cSemester);
map.put(TAG_SCHOOLYEAR, cSchoolYear);
map.put(TAG_SUBJECTCODE, cSubjectCode);
map.put(TAG_DESCRIPTION, cDescription);
map.put(TAG_FINALGRADE, nFGrade);
map.put(TAG_COMPLETIONGRADE, nCGrade);
map.put(TAG_CREDIT, nCredit);
ViewGrades.add(map);
}
The PHP encryption is running .. but when i decrypt it the system returns another encrypted value .. for example the fGrade is 1.0.
the PHP encypted String value is: "PT1RVERSRGU="
the Java decrypted value is: "==QTDRDe"
where did I go wrong? I need help please ..thanks guys!
Base64 has no key, anyone can decode it, change it and replace it. But that may be all you need if you just want to thwart the casual user. You need to define who you are protecting against knowing that every scheme can be compromised.
To encrypt data use AES. Encryption is not easy to get correct. The PHP mcrypt encryption function is flawed, do not use it. Consider RNCryptor-php, it provides a full solution including authentication and key derivation.

java decoding base64 String

I realise this is probably more of a general java question, but since it's running in Notes\ Domino environment, thought I'd check that community first.
Summary:
I don't seem to be able to decode the string: dABlAHMAdAA= using lotus.domino.axis.encoding.Base64 or sun.misc.BASE64Decoder
I know the original text is: test
I confirmed by decoding at http://www5.rptea.com/base64/ it appears it is UTF-16.
As simple test, using either of below:
String s_base64 = "dABlAHMAdAA=";
byte[] byte_base64 = null;
String s_decoded = "";
byte_base64 = new sun.misc.BASE64Decoder().decodeBuffer(s_base64);
s_decoded = new String(byte_base64, "UTF-16");
System.out.println("Test1: " + s_decoded);
byte_base64 = lotus.domino.axis.encoding.Base64.decode(s_base64);
s_decoded = new String(byte_base64, "UTF-16");
System.out.println("Test2: " + s_decoded);
System.out.println("========= FINISH.");
I get the output:
Test1: ????
Test2: ????
If I create String as UTF-8
s_decoded = new String(byte_base64, "UTF-8");
it outputs:
t
no error is thrown, but it doesn't complete the code, doesn't get to the "FINISH".
Detail
I'm accessing an asmx web service, in the SOAP response, some nodes contain base64 encoded data. At this point in time, there is no way to get the service changed, so I am having to XPath and decode myself. Encoded data is either text or html. If I pass the encoded data thru http://www5.rptea.com/base64/ and select UTF-16, it decodes correctly, so I must be doing something incorrectly.
As side note, I encoded "test":
s_base64 = lotus.domino.axis.encoding.Base64.encode(s_text.getBytes());
System.out.println("test1 encodes to: " + s_base64);
s_base64 = new sun.misc.BASE64Encoder().encode(s_text.getBytes());
System.out.println("test2 encodes to: " + s_base64);
they both encode to:
dGVzdA==
...which if you then feed into 2 decoders above, as expected, decodes correctly.
If I go to site above, and encode "test" as UTF-16, I get: dABlAHMAdAA= so that confirms that data is in UTF-16.
It's like the data is genuine base64 data, but the decoder doesn't recognise it as such. I'm slightly stumped at the moment.
Any pointers or comments would be gratefully received.
The string has been encoded in UTF-16LE (little-endian), where the least significant byte is stored first. Java defaults to big-endian. You need to use:
s_decoded = new String(byte_base64, "UTF-16LE");
i have used your sample "dABlAHMAdAA=" on my base64 decode online tool and it seems like you are missing the Apache base64 jar files
Click the link below.
http://www.hosting4free.info/Base64Decode/Base64-Decode.jsp
The code behind the website is
import org.apache.commons.codec.binary.Base64;
public class base64decode
{
public static void main(String[] args) throws UnsupportedEncodingException
{
byte[] decoded = Base64.decodeBase64("YWJjZGVmZw==".getBytes());
System.out.println(new String(decoded) + "\n");
}
}

How to encrypt or tokenize a username and date token?

Need to pass a tokenized (encrypted) username and date from webapp A to webapp B via a url parameter. Something like http://webappB?username=userA&timestamp=13445341313 should be sent as http://webappB?token=geufjsggtj26hjdhcjre87klj3. The receiving webapp B should be able to decode the token into the original parameters.
Which technology offers a simple solution that is available for .NET and java? Thanks
I would like to share the solution that I found after some more research.
I chose a very simple symmetric XOR based scramble method in favour of using encryption across platforms.
A piece of code says more than thousand words :
// webappA, encode URL parameter
byte[] userBytes = username.getBytes("UTF-8");
byte[] keyBytes = key.getBytes("UTF-8");
//XOR scramble
byte[] encrypted = new byte[userBytes.length];
for(int i = 0; i < userBytes.length; i++){
encrypted[i] = (byte)(userBytes[i] ^ keyBytes[i % keyBytes.length]);
}
BASE64Encoder encoder = new BASE64Encoder();
String encoded = encoder.encode(encrypted);
// webappB, decode the parameter
BASE64Decoder decoder = new BASE64Decoder();
byte[] decoded = decoder.decodeBuffer( encoded );
//XOR descramble
byte[] decrypted = new byte[decoded.length];
for(int i = 0; i < decoded.length; i++){
decrypted[i] = (byte)(decoded[i] ^ keyBytes[i % keyBytes.length] );
}
What you've suggested is very simple and doesn't require including technologies outside of what Java and .NET already offer. Simply build up an HTTP request, fire it to the right URL, and listen for the response.
Class References
Java: HttpURLConnectionOracle
.NET: WebRequestMSDN
If you think you'll be doing more of this, or the data gets more frequent, complex, or structured, I highly recommend the ubiquitous SOAPWikipedia protocol for extensibility and modularity.

Categories

Resources