I have a question about how java prints the HexString and how to print it in the same format that C# using the BitConverter does.
We (both) are generating this Hex as result of hashing a string with SHA-1 :
a94a8fe5ccb19ba61c4c873d391e987982fbbd3 (hash for "test" string)
The problem is when we test the hashing in C# , C# prints with uppercase and separated with "-" , like A9-4A-8F .. and so on.
How can I print the same format with java?
The code for hashing and printing is this:
String password = "test";
byte[] key = password.getBytes();
MessageDigest md = MessageDigest.getInstance("SHA-1",new BouncyCastleProvider());
byte[] hash = md.digest(key);
String result = "";
for (byte b : hash) {
result += Integer.toHexString(b & 255);
}
return result;
String result = "";
for (byte b : hash) {
result += Integer.toHexString(b & 255).toUpperCase() + "-";
}
return result.subString(0, result.length()-1);
Related
I have a key, precisely which is to hashed in SHA-512 at my end in Java, I am getting the SHA-512 of the same key in Salesforce, but its not matching,
here is the key
T100375|Z123456|3.00|999999999|https://c.ap2.visual.force.com/apex/ThankYou|45454545|test_1.00_0.00~test_1.00_0.00~test_1.00_0.00|prasad.vandavasi#techprocess.co.in|7506384658|11740|Prasad
Vandavasi|7895455555|Y|F|40000000.00|6274148983DTKQQK
here is the salesforce logic..
String salt = '6274148983DTKQQK' //String.valueOf(Crypto.getRandomInteger());
String key = 'T100375|Z123456|3.00|999999999|https://c.ap2.visual.force.com/apex/ThankYou|45454545|test_1.00_0.00~test_1.00_0.00~test_1.00_0.00|prasad.vandavasi#techprocess.co.in|7506384658|11740|Prasad Vandavasi|7895455555|Y|F|40000000.00|6274148983DTKQQK'
Blob digest = Crypto.generateDigest('SHA-512', Blob.valueOf(key));
which generates following
01b80979c6ea2fb6cca5864386ccc9109f6d05d1d9d1a553b2ac8f82ed347a00ed2d940e5e898c0611ebd4f20e41ed8d9619cec8d6e5e1e5a81e1b5d7e6c7dd3
here is my java code..
public static void main(String[] args)throws Exception
{
String password = "T100375|Z123456|3.00|999999999|https://c.ap2.visual.force.com/apex/ThankYou|45454545|test_1.00_0.00~test_1.00_0.00~test_1.00_0.00|prasad.vandavasi#techprocess.co.in|7506384658|11740|Prasad Vandavasi|7895455555|Y|F|40000000.00|6274148983DTKQQK";
MessageDigest md = MessageDigest.getInstance("SHA-512");
md.update(password.getBytes());
byte byteData[] = md.digest();
//convert the byte to hex format method 1
StringBuffer sb = new StringBuffer();
for (int i = 0; i < byteData.length; i++) {
sb.append(Integer.toString((byteData[i] & 0xff) + 0x100, 16).substring(1));
}
System.out.println("Hex format : " + sb.toString());
//convert the byte to hex format method 2
StringBuffer hexString = new StringBuffer();
for (int i=0;i<byteData.length;i++) {
String hex=Integer.toHexString(0xff & byteData[i]);
if(hex.length()==1) hexString.append('0');
hexString.append(hex);
}
System.out.println("Hex format : " + hexString.toString());
}
which generates following..
d5da285c8eb9e93f55185c36e00efccaf77ea778e3443e43b0f22e14600951c8bd61b847604b010e2ebc9b3fbea06c5b817ac8e560d8ae6e59d8e9cef89842d7
Problem is both of these aren't matching, the keys, they should Ideally right ? what Should I do for them to match ?? I can write Java logic to match, salesforce side is something I have to comply with in my java code, and can not do anything on salesforce side.
I'm trying to validate the content of an XML node with SHA-1 , basically, we generate an SHA-1 hash with the content of that node and both sides (client C# and server Java) should have exactly the same hash.
The problem is , I have checked with a diff tool the content of both texts and there is not any difference. But I'm getting a different hash than the client.
C# hash : 60-53-58-69-29-EB-53-BD-85-31-79-28-A0-F9-42-B6-DE-1B-A6-0A
Java hash: E79D7E6F2A6F5D776447714D896D4C3A0CBC793
The way the client (C#) is generating the hash is this:
try
{
Byte[] stream = null;
using (System.Security.Cryptography.SHA1CryptoServiceProvider shaProvider = new System.Security.Cryptography.SHA1CryptoServiceProvider())
{
stream = shaProvider.ComputeHash(System.Text.Encoding.UTF8.GetBytes(text));
if (stream == null)
{
hash = "Error";
}
else
{
hash = System.BitConverter.ToString(stream);
}
}
}
catch (Exception error)
{
hash = string.Format("Error SHA-1: {0}", error);
}
return hash;
and this is how the server (Java) is generating the hash:
byte[] key = content.getBytes();
MessageDigest md = MessageDigest.getInstance("SHA1");
byte[] hash = md.digest(key);
String result = "";
for (byte b : hash) {
result += Integer.toHexString(b & 255);
}
return result.toUpperCase();
can someone help me ? .. thanks :)
UPDATE:
In order to check what's going on I have checked other ways to get a SHA1 hash in C# and I found this:
/// <summary>
/// Compute hash for string encoded as UTF8
/// </summary>
/// <param name="s">String to be hashed</param>
/// <returns>40-character hex string</returns>
public static string SHA1HashStringForUTF8String(string s)
{
byte[] bytes = Encoding.UTF8.GetBytes(s);
using (var sha1 = SHA1.Create())
{
byte[] hashBytes = sha1.ComputeHash(bytes);
return System.BitConverter.ToString(hashBytes).Replace("-",string.Empty);
}
}
This code gives this output:
E79D07E6F2A6F5D776447714D896D4C3A0CBC793
AND !! I just noticed that Python is giving the same output (sorry, I should double checked this)
So this is the deal
Using this provider: System.Security.Cryptography.SHA1CryptoServiceProvider shaProvider = new System.Security.Cryptography.SHA1CryptoServiceProvider()
Is giving a completly different output on three different machines ..
Using the above method in C# gives the same result as python does, also, for some reason Java is giving a sightly different output:
E79D7E6F2A6F5D776447714D896D4C3A0CBC793
Ideas?, is java the problem? the byte to hex method on java is the problem? there is another alternative?
Try using this as your hashing in C#:
static string Hash(string input)
{
using (SHA1Managed sha1 = new SHA1Managed())
{
var hash = sha1.ComputeHash(Encoding.UTF8.GetBytes(input));
var sb = new StringBuilder(hash.Length * 2);
foreach (byte b in hash)
{
// can be "x2" if you want lowercase
sb.Append(b.ToString("x2"));
}
return sb.ToString();
}
}
Hash("test"); //a94a8fe5ccb19ba61c4c0873d391e987982fbbd3
And then use this as your Java hashing:
private static String convertToHex(byte[] data) {
StringBuilder buf = new StringBuilder();
for (byte b : data) {
int halfbyte = (b >>> 4) & 0x0F;
int two_halfs = 0;
do {
buf.append((0 <= halfbyte) && (halfbyte <= 9) ? (char) ('0' + halfbyte) : (char) ('a' + (halfbyte - 10)));
halfbyte = b & 0x0F;
} while (two_halfs++ < 1);
}
return buf.toString();
}
public static String SHA1(String text) throws NoSuchAlgorithmException, UnsupportedEncodingException {
MessageDigest md = MessageDigest.getInstance("SHA-1");
byte[] textBytes = text.getBytes("iso-8859-1");
md.update(textBytes, 0, textBytes.length);
byte[] sha1hash = md.digest();
return convertToHex(sha1hash);
}
SHA1("test"); //a94a8fe5ccb19ba61c4c0873d391e987982fbbd3
Note you need the following imports:
import java.io.UnsupportedEncodingException; import
java.security.MessageDigest; import
java.security.NoSuchAlgorithmException;
Throws declarations are option, adjust to best fit your code!
Your problem is that you're not hashing the same bytes in both API.
If you choose to modify java's version, it should look like this:
byte[] key = content.getBytes("UTF8");
[...]
If you choose to modify c#' version, it should look like this:
stream = shaProvider.ComputeHash(System.Text.Encoding.UTF16.GetBytes(text));
[...]
Either way, both api should get the key's bytes through the same encoding.
I'm developing an Android app and I need to send some data from server to Android device.
To prevent app from downloading too much data,I wrote a php service, which takes hash (md5 hash of last downloaded data), provided by Android and compares it to latest data's hash on server. If hashes match each other, it prints 'no_new_data', otherwise it prints latest data. Php uses md5($string) method to calculate hash - this part seems to work fine.
The problem is that hash calculated on device never matches server's one - it is wrong, even though string seems to be same. I tried even with changing encoding but it didn't help.
My md5 java code:
public static String md5(String base){
try {
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(base.getBytes());
byte byteData[] = md.digest();
//convert the byte to hex format method 1
StringBuffer sb = new StringBuffer();
for (int i = 0; i < byteData.length; i++) {
sb.append(Integer.toString((byteData[i] & 0xff) + 0x100, 16).substring(1));
}
//System.out.println("Digest(in hex format):: " + sb.toString());
//convert the byte to hex format method 2
StringBuffer hexString = new StringBuffer();
for (int i=0;i<byteData.length;i++) {
String hex=Integer.toHexString(0xff & byteData[i]);
if(hex.length()==1) hexString.append('0');
hexString.append(hex);
}
return hexString.toString();
}catch (Exception e){
return "a";
}
}
Thnks :)
Sometimes md5 hash is different from serverside hash. Try this method.
public static String getMD5Hash(String s) throws NoSuchAlgorithmException {
String result = s;
if (s != null) {
MessageDigest md = MessageDigest.getInstance("MD5"); // or "SHA-1"
md.update(s.getBytes());
BigInteger hash = new BigInteger(1, md.digest());
result = hash.toString(16);
while (result.length() < 32) { // 40 for SHA-1
result = "0" + result;
}
}
return result;
}
Never, ever use String.getBytes(), which depends on the platform-default charset, which is almost never what you want. It seems likely that the platform default charset differs between Android and your server side.
Pass it a Charset instead, e.g.
myString.getBytes(StandardCharsets.UTF_8)
if you have Java 7, or
myString.getBytes("UTF-8")
if you cannot.
I have to "convert" the following .NET code to JAVA :
StringBuilder result = new StringBuilder();
foreach (byte current in hashBytes)
{
result.Append(current.ToString("D").PadLeft(numberOfCharactersInStringRepresentationForByte, '0'));
}
return result.ToString();
I have a hashBytes the byte[] to convert
and
numberOfCharactersInStringRepresentationForByte = 3
How can i do it?
Thanks.
So far i got :
StringBuilder result = new StringBuilder();
for (byte current : hashBytes)
{
int currentUnsigned = (int) current & 0xFF; //Convert the signed byte to unsigned
String currentUnsignedWithPadding = String.format("%3s", currentUnsigned).replace(' ', '0'); //Add tha "0" padding. AABBCCC will be 0AA0BBCCC
result.append(currentUnsignedWithPadding);
}
System.out.println(result.toString());
It seem's to work.
Please let me know if there are some more elegant/optimized ways to do the same.
I'm trying to create a PHP version of an existing JSP program, however I'm stuck at the password encryption part.
Could you please tell me how to convert this one? I know it tries to get the md5() but after that, I don't get it. I get lost in the Stringbuffer and for() parts.
Can you help me out?
public static String encryptPassword( String password )
{
String encrypted = "";
try
{
MessageDigest digest = MessageDigest.getInstance( "MD5" );
byte[] passwordBytes = password.getBytes( );
digest.reset( );
digest.update( passwordBytes );
byte[] message = digest.digest( );
StringBuffer hexString = new StringBuffer();
for ( int i=0; i < message.length; i++)
{
hexString.append( Integer.toHexString(
0xFF & message[ i ] ) );
}
encrypted = hexString.toString();
}
catch( Exception e ) { }
return encrypted;
}
Iraklis should be right. md5() gives you a hex-encoded output string by default. You only get the unencoded bytes like in Java by passing in TRUE for the optional $raw_output argument.
the lengths range from 29 to 32
Then your Java code has a bug. MD5 hashes are always 128 bits (32 hex digits). Here it is:
hexString.append( Integer.toHexString(0xFF & message[ i ] ) );
this will generate 1 instead of 01 for all bytes below 16. What you have stored is a mangled hash, from which you cannot recover the original MD5 value. If you absolutely must keep this broken data, you will have to reproduce the bug in PHP:
function makeBrokenMD5($s) {
$hash= md5($s, TRUE);
$bytes= preg_split('//', $hash, -1, PREG_SPLIT_NO_EMPTY);
$broken= '';
foreach ($bytes as $byte)
$broken.= dechex(ord($byte));
return $broken;
}
It converts the MD5 hash to a string hexadecimal numbers of the least significan byte of the character. In Java all chars are 2 bytes.
In practice this means just the ASCII value.
<?php
$password = "MyPass";
$hash = md5($password);
?>
UPDATE:
There are some discrepancies between the two versions. To fix this see #bobince answer.Here is the test code:
Java
package tests;
import java.security.MessageDigest;
/**
* Created by IntelliJ IDEA.
* User: Iraklis
* Date: 2 Ιουν 2010
* Time: 2:15:03 μμ
* To change this template use File | Settings | File Templates.
*/
public class Md5Test {
public static String encryptPassword(String password) {
String encrypted = "";
try {
MessageDigest digest = MessageDigest.getInstance("MD5");
byte[] passwordBytes = password.getBytes();
digest.reset();
digest.update(passwordBytes);
byte[] message = digest.digest();
StringBuffer hexString = new StringBuffer();
for (int i = 0; i < message.length; i++) {
hexString.append(Integer.toHexString(
0xFF & message[i]));
}
encrypted = hexString.toString();
}
catch (Exception e) {
}
return encrypted;
}
public static void main(String[] args) {
System.out.println("Pass1 md5 = " + encryptPassword("Test123FORXTREMEpass"));
System.out.println("Pass1 md5 = " + encryptPassword("Ijdsaoijds"));
System.out.println("Pass1 md5 = " + encryptPassword("a"));
System.out.println("Pass1 md5 = " + encryptPassword(" "));
}
}
Output:
Pass1 md5 = dc3a7b42a97a3598105936ef22ad2c1
Pass1 md5 = df7ca542bdbf7c4b8776cb21c45e7eef
Pass1 md5 = cc175b9c0f1b6a831c399e269772661
Pass1 md5 = 7215ee9c7d9dc229d2921a40e899ec5f
PHP
<?php
echo "Pass1 md5 = ".md5("Test123FORXTREMEpass")."<BR>";
echo "Pass2 md5 = ".md5("Ijdsaoijds")."<BR>";
echo "Pass3 md5 = ".md5("a")."<BR>";
echo "Pass4 md5 = ".md5(" ")."<BR>";
?>
output:
Pass1 md5 = dc3a7b42a97a35981059036ef22ad2c1
Pass2 md5 = df7ca542bdbf7c4b8776cb21c45e7eef
Pass3 md5 = 0cc175b9c0f1b6a831c399e269772661
Pass4 md5 = 7215ee9c7d9dc229d2921a40e899ec5f
To get the same results in both java and php I used this.
Java(make sure to call the method inside a "try" block):
public static String getHash(String pass) throws Exception
{
MessageDigest md=MessageDigest.getInstance("MD5");
md.update(pass.getBytes(),0,pass.length());
return new BigInteger(1,md.digest()).toString(16);
}
PHP:
<?php
echo md5(pass);
?>
Hope this helps
Edit: If the java variant returns 31 characters, adds a "0" in front of the string to match the php hash which returns 32 characters.